Merge pull request #1439 from Armada651/ogl-stereo-3d

OGL: Stereoscopic 3D Support
This commit is contained in:
Ryan Houdek 2014-11-28 11:45:38 -06:00
commit ce059769f6
48 changed files with 774 additions and 267 deletions

View File

@ -32,3 +32,5 @@ $99 of some treasures
040AE530 3F000063
$End Boss Has No HP
[Video_Stereoscopy]
StereoMonoEFBDepth = True

View File

@ -1,24 +0,0 @@
// Omega's 3D Stereoscopic filtering
// TODO: Need depth info!
void main()
{
// Source Color
float4 c0 = Sample();
const int sep = 5;
float red = c0.r;
float green = c0.g;
float blue = c0.b;
// Left Eye (Red)
float4 c1 = SampleOffset(int2(sep, 0));
red = max(c0.r, c1.r);
// Right Eye (Cyan)
float4 c2 = SampleOffset(int2(-sep, 0));
float cyan = (c2.g + c2.b) / 2.0;
green = max(c0.g, cyan);
blue = max(c0.b, cyan);
SetOutput(float4(red, green, blue, c0.a));
}

View File

@ -1,24 +0,0 @@
// Omega's 3D Stereoscopic filtering (Amber/Blue)
// TODO: Need depth info!
void main()
{
// Source Color
float4 c0 = Sample();
float sep = 5.0;
float red = c0.r;
float green = c0.g;
float blue = c0.b;
// Left Eye (Amber)
float4 c2 = SampleLocation(GetCoordinates() + float2(sep,0.0)*GetInvResolution()).rgba;
float amber = (c2.r + c2.g) / 2.0;
red = max(c0.r, amber);
green = max(c0.g, amber);
// Right Eye (Blue)
float4 c1 = SampleLocation(GetCoordinates() + float2(-sep,0.0)*GetInvResolution()).rgba;
blue = max(c0.b, c1.b);
SetOutput(float4(red, green, blue, c0.a));
}

View File

@ -351,6 +351,13 @@ void Matrix44::Translate(Matrix44 &mtx, const float vec[3])
mtx.data[11] = vec[2];
}
void Matrix44::Shear(Matrix44 &mtx, const float a, const float b)
{
LoadIdentity(mtx);
mtx.data[2] = a;
mtx.data[6] = b;
}
void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result)
{
MatrixMul(4, a.data, b.data, result.data);

View File

@ -232,6 +232,7 @@ public:
static void Set(Matrix44 &mtx, const float mtxArray[16]);
static void Translate(Matrix44 &mtx, const float vec[3]);
static void Shear(Matrix44 &mtx, const float a, const float b = 0);
static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result);

View File

@ -81,6 +81,11 @@ static const struct
{ "FreelookZoomOut", 83 /* 'S' */, 4 /* wxMOD_SHIFT */ },
{ "FreelookReset", 82 /* 'R' */, 4 /* wxMOD_SHIFT */ },
{ "IncreaseSeparation", 0, 0 /* wxMOD_NONE */ },
{ "DecreaseSeparation", 0, 0 /* wxMOD_NONE */ },
{ "IncreaseConvergence", 0, 0 /* wxMOD_NONE */ },
{ "DecreaseConvergence", 0, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot1", 340 /* WXK_F1 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot2", 341 /* WXK_F2 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot3", 342 /* WXK_F3 */, 0 /* wxMOD_NONE */ },

View File

@ -54,6 +54,11 @@ enum Hotkey
HK_FREELOOK_ZOOM_OUT,
HK_FREELOOK_RESET,
HK_INCREASE_SEPARATION,
HK_DECREASE_SEPARATION,
HK_INCREASE_CONVERGENCE,
HK_DECREASE_CONVERGENCE,
HK_LOAD_STATE_SLOT_1,
HK_LOAD_STATE_SLOT_2,
HK_LOAD_STATE_SLOT_3,

View File

@ -1123,6 +1123,26 @@ void CFrame::OnKeyDown(wxKeyEvent& event)
{
State::Load(g_saveSlot);
}
else if (IsHotkey(event, HK_INCREASE_SEPARATION))
{
if (++g_Config.iStereoSeparation > 100)
g_Config.iStereoSeparation = 100;
}
else if (IsHotkey(event, HK_DECREASE_SEPARATION))
{
if (--g_Config.iStereoSeparation < 0)
g_Config.iStereoSeparation = 0;
}
else if (IsHotkey(event, HK_INCREASE_CONVERGENCE))
{
if (++g_Config.iStereoConvergence > 500)
g_Config.iStereoConvergence = 500;
}
else if (IsHotkey(event, HK_DECREASE_CONVERGENCE))
{
if (--g_Config.iStereoConvergence < 0)
g_Config.iStereoConvergence = 0;
}
else
{

View File

@ -238,6 +238,11 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls()
_("Freelook Zoom Out"),
_("Freelook Reset"),
_("Increase Stereocopy Separation"),
_("Decrease Stereocopy Separation"),
_("Increase Stereocopy Convergence"),
_("Decrease Stereocopy Convergence"),
_("Load State Slot 1"),
_("Load State Slot 2"),
_("Load State Slot 3"),

View File

@ -149,6 +149,10 @@ static wxString crop_desc = wxTRANSLATE("Crop the picture from 4:3 to 5:4 or fro
static wxString ppshader_desc = wxTRANSLATE("Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off).");
static wxString cache_efb_copies_desc = wxTRANSLATE("Slightly speeds up EFB to RAM copies by sacrificing emulation accuracy.\nSometimes also increases visual quality.\nIf you're experiencing any issues, try raising texture cache accuracy or disable this option.\n\nIf unsure, leave this unchecked.");
static wxString shader_errors_desc = wxTRANSLATE("Usually if shader compilation fails, an error message is displayed.\nHowever, one may skip the popups to allow interruption free gameplay by checking this option.\n\nIf unsure, leave this unchecked.");
static wxString stereo_3d_desc = wxTRANSLATE("Select the stereoscopic 3D mode, stereoscopy allows you to get a better feeling of depth if you have the necessary hardware.\nSide-by-Side and Top-and-Bottom are used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHeavily decreases emulation speed and sometimes causes issues.\n\nIf unsure, select Off.");
static wxString stereo_separation_desc = wxTRANSLATE("Control the separation distance, this is the distance between the virtual cameras.\nA higher value creates a stronger feeling of depth while a lower value is more comfortable.");
static wxString stereo_convergence_desc = wxTRANSLATE("Control the convergence distance, this controls the apparant distance of virtual objects.\nA higher value creates stronger out-of-screen effects while a lower value is more comfortable.");
static wxString stereo_swap_desc = wxTRANSLATE("Swap the left and right eye, mostly useful if you want to view side-by-side cross-eyed.\n\nIf unsure, leave this unchecked.");
#if !defined(__APPLE__)
@ -396,7 +400,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
if (vconfig.backend_info.PPShaders.size())
{
wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5);
wxChoice *const choice_ppshader = new wxChoice(page_enh, -1);
choice_ppshader = new wxChoice(page_enh, -1);
RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc));
choice_ppshader->AppendString(_("(off)"));
@ -425,6 +429,11 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
szr_pp->Add(button_config_pp);
szr_enh->Add(szr_pp);
}
else
{
choice_ppshader = nullptr;
button_config_pp = nullptr;
}
// Scaled copy, PL, Bilinear filter
szr_enh->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"), wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled));
@ -438,6 +447,36 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_enh_main->Add(group_enh, 0, wxEXPAND | wxALL, 5);
// - stereoscopy
if (vconfig.backend_info.bSupportsStereoscopy && vconfig.iStereoMode > 0)
{
wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5);
const wxString stereo_choices[] = { "Off", "Side-by-Side", "Top-and-Bottom", "Anaglyph" };
szr_stereo->Add(new wxStaticText(page_enh, -1, _("Stereoscopic 3D Mode:")), 1, wxALIGN_CENTER_VERTICAL, 0);
szr_stereo->Add(CreateChoice(page_enh, vconfig.iStereoMode, wxGetTranslation(stereo_3d_desc), 4, stereo_choices));
wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoSeparation, 0, 100, wxDefaultPosition, wxDefaultSize);
sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoSep, this);
RegisterControl(sep_slider, wxGetTranslation(stereo_separation_desc));
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Separation:")), 1, wxALIGN_CENTER_VERTICAL, 0);
szr_stereo->Add(sep_slider, 0, wxEXPAND | wxRIGHT);
wxSlider* const conv_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoConvergence, 0, 500, wxDefaultPosition, wxDefaultSize);
conv_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoFoc, this);
RegisterControl(conv_slider, wxGetTranslation(stereo_convergence_desc));
szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")), 1, wxALIGN_CENTER_VERTICAL, 0);
szr_stereo->Add(conv_slider, 0, wxEXPAND | wxRIGHT);
szr_stereo->Add(CreateCheckBox(page_enh, _("Swap Eyes"), wxGetTranslation(stereo_swap_desc), vconfig.bStereoSwapEyes));
wxStaticBoxSizer* const group_stereo = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Stereoscopy"));
group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxALL, 5);
}
szr_enh_main->AddStretchSpacer();
CreateDescriptionArea(page_enh, szr_enh_main);

View File

@ -165,6 +165,20 @@ protected:
ev.Skip();
}
void Event_StereoSep(wxCommandEvent &ev)
{
vconfig.iStereoSeparation = ev.GetInt();
ev.Skip();
}
void Event_StereoFoc(wxCommandEvent &ev)
{
vconfig.iStereoConvergence = ev.GetInt();
ev.Skip();
}
void Event_ClickClose(wxCommandEvent&);
void Event_Close(wxCloseEvent&);
@ -184,6 +198,12 @@ protected:
virtual_xfb->Enable(vconfig.bUseXFB);
real_xfb->Enable(vconfig.bUseXFB);
// PP Shaders
if (choice_ppshader)
choice_ppshader->Enable(vconfig.iStereoMode != STEREO_ANAGLYPH);
if (button_config_pp)
button_config_pp->Enable(vconfig.iStereoMode != STEREO_ANAGLYPH);
// Things which shouldn't be changed during emulation
if (Core::IsRunning())
{
@ -248,6 +268,8 @@ protected:
wxCheckBox* progressive_scan_checkbox;
wxChoice* choice_ppshader;
std::map<wxWindow*, wxString> ctrl_descs; // maps setting controls to their descriptions
std::map<wxWindow*, wxStaticText*> desc_texts; // maps dialog tabs (which are the parents of the setting controls) to their description text objects

View File

@ -172,7 +172,7 @@ bool LineGeometryShader::SetShader(u32 components, float lineWidth,
static char buffer[16384];
ShaderCode code;
code.SetBuffer(buffer);
GenerateVSOutputStructForGS(code, API_D3D);
GenerateVSOutputStruct(code, API_D3D);
code.Write("\n%s", LINE_GS_COMMON);
std::stringstream numTexCoordsStream;

View File

@ -166,7 +166,7 @@ bool PointGeometryShader::SetShader(u32 components, float pointSize,
static char buffer[16384];
ShaderCode code;
code.SetBuffer(buffer);
GenerateVSOutputStructForGS(code, API_D3D);
GenerateVSOutputStruct(code, API_D3D);
code.Write("\n%s", POINT_GS_COMMON);
std::stringstream numTexCoordsStream;

View File

@ -43,6 +43,9 @@ private:
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) override;
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;};
void CompileShaders() override { }
void DeleteShaders() override { }
};
}

View File

@ -78,6 +78,7 @@ void InitBackendInfo()
g_Config.backend_info.bSupportsPrimitiveRestart = true;
g_Config.backend_info.bSupportsOversizedViewports = false;
g_Config.backend_info.bSupportsBBox = false; // TODO: not implemented
g_Config.backend_info.bSupportsStereoscopy = false; // TODO: not implemented
IDXGIFactory* factory;
IDXGIAdapter* ad;

View File

@ -21,7 +21,6 @@ int FramebufferManager::m_targetHeight;
int FramebufferManager::m_msaaSamples;
GLenum FramebufferManager::m_textureType;
GLuint FramebufferManager::m_efbFramebuffer;
GLuint FramebufferManager::m_xfbFramebuffer;
GLuint FramebufferManager::m_efbColor;
@ -72,42 +71,45 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
m_efbDepth = glObj[1];
m_efbColorSwap = glObj[2];
m_EFBLayers = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1;
// OpenGL MSAA textures are a different kind of texture type and must be allocated
// with a different function, so we create them separately.
if (m_msaaSamples <= 1)
{
m_textureType = GL_TEXTURE_2D;
m_textureType = GL_TEXTURE_2D_ARRAY;
glBindTexture(m_textureType, m_efbColor);
glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(m_textureType, m_efbDepth);
glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(m_textureType, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexImage3D(m_textureType, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glBindTexture(m_textureType, m_efbColorSwap);
glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(m_textureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
else
{
m_textureType = GL_TEXTURE_2D_MULTISAMPLE;
m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
GLenum resolvedType = GL_TEXTURE_2D_ARRAY;
glBindTexture(m_textureType, m_efbColor);
glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false);
glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false);
glBindTexture(m_textureType, m_efbDepth);
glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, false);
glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, false);
glBindTexture(m_textureType, m_efbColorSwap);
glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false);
glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false);
glBindTexture(m_textureType, 0);
// Although we are able to access the multisampled texture directly, we don't do it everywhere.
@ -118,23 +120,23 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
m_resolvedColorTexture = glObj[0];
m_resolvedDepthTexture = glObj[1];
glBindTexture(GL_TEXTURE_2D, m_resolvedColorTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(resolvedType, m_resolvedColorTexture);
glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(resolvedType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(resolvedType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(resolvedType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, m_resolvedDepthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glBindTexture(resolvedType, m_resolvedDepthTexture);
glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(resolvedType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(resolvedType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(resolvedType, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
// Bind resolved textures to resolved framebuffer.
glGenFramebuffers(1, &m_resolvedFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_resolvedColorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_resolvedDepthTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_resolvedColorTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_resolvedDepthTexture, 0);
}
// Create XFB framebuffer; targets will be created elsewhere.
@ -143,8 +145,8 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
// Bind target textures to EFB framebuffer.
glGenFramebuffers(1, &m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_textureType, m_efbDepth, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_efbDepth, 0);
// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
glViewport(0, 0, m_targetWidth, m_targetHeight);
@ -168,9 +170,9 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
{
// non-msaa, so just fetch the pixel
sampler =
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"vec4 sampleEFB(ivec2 pos) {\n"
" return texelFetch(samp9, pos, 0);\n"
" return texelFetch(samp9, ivec3(pos, 0), 0);\n"
"}\n";
}
else if (g_ogl_config.bSupportSampleShading)
@ -179,9 +181,9 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
// This will lead to sample shading, but it's the only way to not loose
// the values of each sample.
sampler =
"SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n"
"vec4 sampleEFB(ivec2 pos) {\n"
" return texelFetch(samp9, pos, gl_SampleID);\n"
" return texelFetch(samp9, ivec3(pos, 0), gl_SampleID);\n"
"}\n";
}
else
@ -190,11 +192,11 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
std::stringstream samples;
samples << m_msaaSamples;
sampler =
"SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n"
"vec4 sampleEFB(ivec2 pos) {\n"
" vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n"
" for(int i=0; i<" + samples.str() + "; i++)\n"
" color += texelFetch(samp9, pos, i);\n"
" color += texelFetch(samp9, ivec3(pos, 0), i);\n"
" return color / " + samples.str() + ";\n"
"}\n";
}
@ -365,7 +367,7 @@ void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
src_texture = m_efbColor;
m_efbColor = m_efbColorSwap;
m_efbColorSwap = src_texture;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0);
glViewport(0,0, m_targetWidth, m_targetHeight);
glActiveTexture(GL_TEXTURE0 + 9);
@ -397,7 +399,7 @@ void XFBSource::CopyEFB(float Gamma)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer());
// Bind texture.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
glBlitFramebuffer(
0, 0, texWidth, texHeight,
@ -419,11 +421,11 @@ XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, un
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0 + 9);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, target_width, target_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, target_width, target_height, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
return new XFBSource(texture);
return new XFBSource(texture, m_EFBLayers);
}
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)

View File

@ -47,13 +47,14 @@ namespace OGL
struct XFBSource : public XFBSourceBase
{
XFBSource(GLuint tex) : texture(tex) {}
XFBSource(GLuint tex, int layers) : texture(tex), m_layers(layers) {}
~XFBSource();
void CopyEFB(float Gamma) override;
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
const GLuint texture;
const int m_layers;
};
class FramebufferManager : public FramebufferManagerBase
@ -100,7 +101,6 @@ private:
static int m_msaaSamples;
static GLenum m_textureType;
static GLuint m_efbFramebuffer;
static GLuint m_xfbFramebuffer;
static GLuint m_efbColor;

View File

@ -37,6 +37,8 @@ static char s_vertex_shader[] =
"}\n";
OpenGLPostProcessing::OpenGLPostProcessing()
: m_initialized(false)
, m_anaglyph(false)
{
CreateHeader();
@ -46,8 +48,6 @@ OpenGLPostProcessing::OpenGLPostProcessing()
glGenBuffers(1, &m_attribute_vbo);
glGenVertexArrays(1, &m_attribute_vao);
}
m_initialized = false;
}
OpenGLPostProcessing::~OpenGLPostProcessing()
@ -62,7 +62,7 @@ OpenGLPostProcessing::~OpenGLPostProcessing()
}
void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle dst,
int src_texture, int src_width, int src_height)
int src_texture, int src_width, int src_height, int layer)
{
ApplyShader();
@ -79,6 +79,7 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle
glUniform4f(m_uniform_src_rect, src.left / (float) src_width, src.bottom / (float) src_height,
src.GetWidth() / (float) src_width, src.GetHeight() / (float) src_height);
glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed());
glUniform1i(m_uniform_layer, layer);
if (m_config.IsDirty())
{
@ -151,25 +152,29 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle
}
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, src_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void OpenGLPostProcessing::ApplyShader()
{
// shader didn't changed
if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader)
if (m_initialized && m_config.GetShader() == g_ActiveConfig.sPostProcessingShader &&
((g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH) == m_anaglyph))
return;
m_shader.Destroy();
m_uniform_bindings.clear();
// load shader from disk
std::string default_shader = "void main() { SetOutput(Sample()); }";
// load shader code
std::string code = "";
if (g_ActiveConfig.sPostProcessingShader != "")
std::string default_shader = "void main() { SetOutput(Sample()); }\n";
if (g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH)
code = "void main() { SetOutput(float4(pow(0.7 * SampleLayer(0).g + 0.3 * SampleLayer(0).b, 1.5), SampleLayer(1).gba)); }\n";
else if (g_ActiveConfig.sPostProcessingShader != "")
code = m_config.LoadShader();
if (code == "")
@ -195,6 +200,7 @@ void OpenGLPostProcessing::ApplyShader()
m_uniform_resolution = glGetUniformLocation(m_shader.glprogid, "resolution");
m_uniform_time = glGetUniformLocation(m_shader.glprogid, "time");
m_uniform_src_rect = glGetUniformLocation(m_shader.glprogid, "src_rect");
m_uniform_layer = glGetUniformLocation(m_shader.glprogid, "layer");
if (m_attribute_workaround)
{
@ -218,6 +224,7 @@ void OpenGLPostProcessing::ApplyShader()
std::string glsl_name = "option_" + it.first;
m_uniform_bindings[it.first] = glGetUniformLocation(m_shader.glprogid, glsl_name.c_str());
}
m_anaglyph = g_ActiveConfig.iStereoMode == STEREO_ANAGLYPH;
m_initialized = true;
}
@ -228,7 +235,7 @@ void OpenGLPostProcessing::CreateHeader()
// Shouldn't be accessed directly by the PP shader
// Texture sampler
"SAMPLER_BINDING(8) uniform sampler2D samp8;\n"
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
// Output variable
"out float4 ocol0;\n"
@ -238,19 +245,26 @@ void OpenGLPostProcessing::CreateHeader()
"uniform float4 resolution;\n"
// Time
"uniform uint time;\n"
// Layer
"uniform int layer;\n"
// Interfacing functions
"float4 Sample()\n"
"{\n"
"\treturn texture(samp9, uv0);\n"
"\treturn texture(samp9, float3(uv0, layer));\n"
"}\n"
"float4 SampleLocation(float2 location)\n"
"{\n"
"\treturn texture(samp9, location);\n"
"\treturn texture(samp9, float3(location, layer));\n"
"}\n"
"#define SampleOffset(offset) textureOffset(samp9, uv0, offset)\n"
"float4 SampleLayer(int layer)\n"
"{\n"
"\treturn texture(samp9, float3(uv0, layer));\n"
"}\n"
"#define SampleOffset(offset) textureOffset(samp9, float3(uv0, layer), offset)\n"
"float4 SampleFontLocation(float2 location)\n"
"{\n"

View File

@ -23,15 +23,17 @@ public:
~OpenGLPostProcessing();
void BlitFromTexture(TargetRectangle src, TargetRectangle dst,
int src_texture, int src_width, int src_height) override;
int src_texture, int src_width, int src_height, int layer) override;
void ApplyShader() override;
private:
bool m_initialized;
bool m_anaglyph;
SHADER m_shader;
GLuint m_uniform_resolution;
GLuint m_uniform_src_rect;
GLuint m_uniform_time;
GLuint m_uniform_layer;
std::string m_glsl_header;
// These are only used when working around Qualcomm's broken attributeless rendering

View File

@ -36,6 +36,7 @@ ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
SHADERUID ProgramShaderCache::last_uid;
UidChecker<PixelShaderUid,PixelShaderCode> ProgramShaderCache::pixel_uid_checker;
UidChecker<VertexShaderUid,VertexShaderCode> ProgramShaderCache::vertex_uid_checker;
UidChecker<GeometryShaderUid,ShaderCode> ProgramShaderCache::geometry_uid_checker;
static char s_glsl_header[1024] = "";
@ -196,13 +197,17 @@ SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components
VertexShaderCode vcode;
PixelShaderCode pcode;
ShaderCode gcode;
GenerateVertexShaderCode(vcode, components, API_OPENGL);
GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components);
if (g_ActiveConfig.iStereoMode > 0)
GenerateGeometryShaderCode(gcode, components, API_OPENGL);
if (g_ActiveConfig.bEnableShaderDebugging)
{
newentry.shader.strvprog = vcode.GetBuffer();
newentry.shader.strpprog = pcode.GetBuffer();
newentry.shader.strgprog = gcode.GetBuffer();
}
#if defined(_DEBUG) || defined(DEBUGFAST)
@ -214,10 +219,16 @@ SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components
filename = StringFromFormat("%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
SaveData(filename, pcode.GetBuffer());
if (gcode.GetBuffer() != nullptr)
{
filename = StringFromFormat("%sgs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
SaveData(filename, gcode.GetBuffer());
}
}
#endif
if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer()))
if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return nullptr;
@ -231,15 +242,21 @@ SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components
return &last_entry->shader;
}
bool ProgramShaderCache::CompileShader(SHADER& shader, const char* vcode, const char* pcode)
bool ProgramShaderCache::CompileShader(SHADER& shader, const char* vcode, const char* pcode, const char* gcode)
{
GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode);
GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode);
if (!vsid || !psid)
// Optional geometry shader
GLuint gsid = 0;
if (gcode)
gsid = CompileSingleShader(GL_GEOMETRY_SHADER, gcode);
if (!vsid || !psid || (gcode && !gsid))
{
glDeleteShader(vsid);
glDeleteShader(psid);
glDeleteShader(gsid);
return false;
}
@ -247,6 +264,8 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const char* vcode, const
glAttachShader(pid, vsid);
glAttachShader(pid, psid);
if (gsid)
glAttachShader(pid, gsid);
if (g_ogl_config.bSupportsGLSLCache)
glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
@ -258,6 +277,7 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const char* vcode, const
// original shaders aren't needed any more
glDeleteShader(vsid);
glDeleteShader(psid);
glDeleteShader(gsid);
GLint linkStatus;
glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus);
@ -273,7 +293,10 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const char* vcode, const
std::string filename = StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
OpenFStream(file, filename, std::ios_base::out);
file << s_glsl_header << vcode << s_glsl_header << pcode << infoLog;
file << s_glsl_header << vcode << s_glsl_header << pcode;
if (gcode)
file << s_glsl_header << gcode;
file << infoLog;
file.close();
if (linkStatus != GL_TRUE)
@ -324,11 +347,11 @@ GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const char* code)
GLsizei charsWritten;
GLchar* infoLog = new GLchar[length];
glGetShaderInfoLog(result, length, &charsWritten, infoLog);
ERROR_LOG(VIDEO, "%s Shader info log:\n%s", type==GL_VERTEX_SHADER ? "VS" : "PS", infoLog);
ERROR_LOG(VIDEO, "%s Shader info log:\n%s", type==GL_VERTEX_SHADER ? "VS" : type==GL_FRAGMENT_SHADER ? "PS" : "GS", infoLog);
std::string filename = StringFromFormat("%sbad_%s_%04i.txt",
File::GetUserPath(D_DUMP_IDX).c_str(),
type==GL_VERTEX_SHADER ? "vs" : "ps",
type==GL_VERTEX_SHADER ? "vs" : type==GL_FRAGMENT_SHADER ? "ps" : "gs",
num_failures++);
std::ofstream file;
OpenFStream(file, filename, std::ios_base::out);
@ -338,7 +361,7 @@ GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const char* code)
if (compileStatus != GL_TRUE)
{
PanicAlert("Failed to compile %s shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s, %s, %s):\n%s",
type == GL_VERTEX_SHADER ? "vertex" : "pixel",
type == GL_VERTEX_SHADER ? "vertex" : type==GL_FRAGMENT_SHADER ? "pixel" : "geometry",
filename.c_str(),
g_ogl_config.gl_vendor,
g_ogl_config.gl_renderer,
@ -365,6 +388,7 @@ void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode,
{
GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components);
GetVertexShaderUid(uid->vuid, components, API_OPENGL);
GetGeometryShaderUid(uid->guid, components, API_OPENGL);
if (g_ActiveConfig.bEnableShaderDebugging)
{
@ -375,6 +399,10 @@ void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode,
VertexShaderCode vcode;
GenerateVertexShaderCode(vcode, components, API_OPENGL);
vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v");
ShaderCode gcode;
GenerateGeometryShaderCode(gcode, components, API_OPENGL);
geometry_uid_checker.AddToIndexAndCheck(gcode, uid->guid, "Geometry", "g");
}
}
@ -486,6 +514,7 @@ void ProgramShaderCache::CreateHeader()
"%s\n" // sample shading
"%s\n" // Sampler binding
"%s\n" // storage buffer
"%s\n" // shader5
// Precision defines for GLSL ES
"%s\n"
@ -518,6 +547,7 @@ void ProgramShaderCache::CreateHeader()
, (g_ogl_config.bSupportSampleShading) ? "#extension GL_ARB_sample_shading : enable" : ""
, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "#define SAMPLER_BINDING(x) layout(binding = x)" : "#define SAMPLER_BINDING(x)"
, g_ActiveConfig.backend_info.bSupportsBBox ? "#extension GL_ARB_shader_storage_buffer_object : enable" : ""
, g_ActiveConfig.backend_info.bSupportsGSInstancing ? "#extension GL_ARB_gpu_shader5 : enable" : ""
, v>=GLSLES_300 ? "precision highp float;" : ""
, v>=GLSLES_300 ? "precision highp int;" : ""

View File

@ -7,6 +7,7 @@
#include "Common/LinearDiskCache.h"
#include "Core/ConfigManager.h"
#include "VideoBackends/OGL/GLUtil.h"
#include "VideoCommon/GeometryShaderGen.h"
#include "VideoCommon/PixelShaderGen.h"
#include "VideoCommon/VertexShaderGen.h"
@ -18,10 +19,11 @@ class SHADERUID
public:
VertexShaderUid vuid;
PixelShaderUid puid;
GeometryShaderUid guid;
SHADERUID() {}
SHADERUID(const SHADERUID& r) : vuid(r.vuid), puid(r.puid) {}
SHADERUID(const SHADERUID& r) : vuid(r.vuid), puid(r.puid), guid(r.guid) {}
bool operator <(const SHADERUID& r) const
{
@ -34,12 +36,18 @@ public:
if (vuid < r.vuid)
return true;
if (r.vuid < vuid)
return false;
if (guid < r.guid)
return true;
return false;
}
bool operator ==(const SHADERUID& r) const
{
return puid == r.puid && vuid == r.vuid;
return puid == r.puid && vuid == r.vuid && guid == r.guid;
}
};
@ -54,7 +62,7 @@ struct SHADER
}
GLuint glprogid; // OpenGL program id
std::string strvprog, strpprog;
std::string strvprog, strpprog, strgprog;
void SetProgramVariables();
void SetProgramBindings();
@ -83,7 +91,7 @@ public:
static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components);
static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
static bool CompileShader(SHADER &shader, const char* vcode, const char* pcode);
static bool CompileShader(SHADER &shader, const char* vcode, const char* pcode, const char* gcode = nullptr);
static GLuint CompileSingleShader(GLuint type, const char *code);
static void UploadConstants();
@ -104,6 +112,7 @@ private:
static UidChecker<PixelShaderUid,PixelShaderCode> pixel_uid_checker;
static UidChecker<VertexShaderUid,VertexShaderCode> vertex_uid_checker;
static UidChecker<GeometryShaderUid,ShaderCode> geometry_uid_checker;
static u32 s_ubo_buffer_size;
static s32 s_ubo_align;

View File

@ -89,6 +89,8 @@ static RasterFont* s_pfont = nullptr;
static int s_MSAASamples = 1;
static int s_LastMultisampleMode = 0;
static bool s_LastStereo = false;
static u32 s_blendMode;
static bool s_vsync;
@ -204,6 +206,10 @@ static void GLAPIENTRY ClearDepthf(GLfloat depthval)
{
glClearDepth(depthval);
}
static void GLAPIENTRY FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level)
{
glFramebufferTextureLayer(target, attachment, texture, level, 0);
}
static void InitDriverInfo()
{
@ -460,11 +466,17 @@ Renderer::Renderer()
glClearDepthf = ClearDepthf;
}
if (GLExtensions::Version() < 320 || GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
{
glFramebufferTexture = FramebufferTexture;
}
g_Config.backend_info.bSupportsDualSourceBlend = GLExtensions::Supports("GL_ARB_blend_func_extended");
g_Config.backend_info.bSupportsPrimitiveRestart = !DriverDetails::HasBug(DriverDetails::BUG_PRIMITIVERESTART) &&
((GLExtensions::Version() >= 310) || GLExtensions::Supports("GL_NV_primitive_restart"));
g_Config.backend_info.bSupportsEarlyZ = GLExtensions::Supports("GL_ARB_shader_image_load_store");
g_Config.backend_info.bSupportsBBox = GLExtensions::Supports("GL_ARB_shader_storage_buffer_object");
g_Config.backend_info.bSupportsGSInstancing = GLExtensions::Supports("GL_ARB_gpu_shader5");
// Desktop OpenGL supports the binding layout if it supports 420pack
// OpenGL ES 3.1 supports it implicitly without an extension
@ -493,6 +505,8 @@ Renderer::Renderer()
g_Config.backend_info.bSupportsBindingLayout = true;
g_Config.backend_info.bSupportsEarlyZ = true;
}
// TODO: OpenGL ES 3.1 provides the necessary features as extensions.
g_Config.backend_info.bSupportsStereoscopy = false;
}
else
{
@ -507,11 +521,13 @@ Renderer::Renderer()
{
g_ogl_config.eSupportedGLSLVersion = GLSL_130;
g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
g_Config.backend_info.bSupportsStereoscopy = false; // geometry shaders are only supported on glsl150+
}
else if (strstr(g_ogl_config.glsl_version, "1.40"))
{
g_ogl_config.eSupportedGLSLVersion = GLSL_140;
g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
g_Config.backend_info.bSupportsStereoscopy = false; // geometry shaders are only supported on glsl150+
}
else
{
@ -545,6 +561,9 @@ Renderer::Renderer()
bSuccess = false;
}
if (g_Config.iStereoMode > 0 && !g_Config.backend_info.bSupportsStereoscopy)
OSD::AddMessage("Stereoscopic 3D isn't supported by your GPU, support for OpenGL 3.2 is required.", 10000);
if (!bSuccess)
{
// Not all needed extensions are supported, so we have to stop here.
@ -556,6 +575,7 @@ Renderer::Renderer()
if (g_ogl_config.max_samples < 1 || !g_ogl_config.bSupportsMSAA)
g_ogl_config.max_samples = 1;
g_Config.VerifyValidity();
UpdateActiveConfig();
OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s",
@ -563,7 +583,7 @@ Renderer::Renderer()
g_ogl_config.gl_renderer,
g_ogl_config.gl_version), 5000);
WARN_LOG(VIDEO,"Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s",
WARN_LOG(VIDEO,"Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s",
g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ",
g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ",
g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ",
@ -573,12 +593,14 @@ Renderer::Renderer()
g_ogl_config.bSupportsGLBufferStorage ? "" : "BufferStorage ",
g_ogl_config.bSupportsGLSync ? "" : "Sync ",
g_ogl_config.bSupportsMSAA ? "" : "MSAA ",
g_ogl_config.bSupportSampleShading ? "" : "SSAA "
g_ogl_config.bSupportSampleShading ? "" : "SSAA ",
g_ActiveConfig.backend_info.bSupportsGSInstancing ? "" : "GSInstancing "
);
s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
ApplySSAASettings();
s_LastStereo = g_ActiveConfig.iStereoMode > 0;
// Decide framebuffer size
s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
@ -1493,7 +1515,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
sourceRc.right -= fbStride - fbWidth;
m_post_processor->BlitFromTexture(sourceRc, drawRc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight);
// TODO: Virtual XFB stereoscopic 3D support.
m_post_processor->BlitFromTexture(sourceRc, drawRc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight, 1);
}
}
else
@ -1503,7 +1526,18 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
// for msaa mode, we must resolve the efb content to non-msaa
GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(rc);
m_post_processor->BlitFromTexture(targetRc, flipped_trc, tex, s_target_width, s_target_height);
if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB)
{
TargetRectangle leftRc, rightRc;
ConvertStereoRectangle(flipped_trc, leftRc, rightRc);
m_post_processor->BlitFromTexture(targetRc, leftRc, tex, s_target_width, s_target_height, 0);
m_post_processor->BlitFromTexture(targetRc, rightRc, tex, s_target_width, s_target_height, 1);
}
else
{
m_post_processor->BlitFromTexture(targetRc, flipped_trc, tex, s_target_width, s_target_height);
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
@ -1652,15 +1686,16 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
s_LastEFBScale = g_ActiveConfig.iEFBScale;
}
if (xfbchanged || WindowResized || (s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode))
if (xfbchanged || WindowResized || (s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode) || (s_LastStereo != (g_ActiveConfig.iStereoMode > 0)))
{
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode)
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || s_LastMultisampleMode != g_ActiveConfig.iMultisampleMode || s_LastStereo != (g_ActiveConfig.iStereoMode > 0))
{
s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
ApplySSAASettings();
s_LastStereo = g_ActiveConfig.iStereoMode > 0;
delete g_framebuffer_manager;
g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,

View File

@ -98,14 +98,14 @@ void TextureCache::TCacheEntry::Bind(unsigned int stage)
s_ActiveTexture = stage;
}
glBindTexture(GL_TEXTURE_2D, texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
s_Textures[stage] = texture;
}
}
bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level)
{
return SaveTexture(filename, GL_TEXTURE_2D, texture, virtual_width, virtual_height, level);
return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, texture, virtual_width, virtual_height, level);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
@ -172,8 +172,8 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
entry.pcfmt = pcfmt;
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, entry.texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex_levels - 1);
glBindTexture(GL_TEXTURE_2D_ARRAY, entry.texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, tex_levels - 1);
entry.Load(width, height, expanded_width, 0);
@ -189,12 +189,12 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
if (pcfmt != PC_TEX_FMT_DXT1)
{
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_iformat, width, height, 1, 0, gl_format, gl_type, temp);
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -213,21 +213,20 @@ TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
{
TCacheEntry *const entry = new TCacheEntry;
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, entry->texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, entry->texture);
const GLenum
gl_format = GL_RGBA,
gl_iformat = GL_RGBA,
gl_type = GL_UNSIGNED_BYTE;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_h, 0, gl_format, gl_type, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, gl_iformat, scaled_tex_w, scaled_tex_h, FramebufferManager::GetEFBLayers(), 0, gl_format, gl_type, nullptr);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glGenFramebuffers(1, &entry->framebuffer);
FramebufferManager::SetFramebuffer(entry->framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, entry->texture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, entry->texture, 0);
SetStage();
@ -251,7 +250,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
FramebufferManager::SetFramebuffer(framebuffer);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, read_texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture);
glViewport(0, 0, virtual_width, virtual_height);
@ -309,34 +308,60 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
{
static int count = 0;
SaveTexture(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
count++), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
count++), GL_TEXTURE_2D_ARRAY, texture, virtual_width, virtual_height, 0);
}
g_renderer->RestoreAPIState();
}
TextureCache::TextureCache()
{
CompileShaders();
s_ActiveTexture = -1;
for (auto& gtex : s_Textures)
gtex = -1;
}
TextureCache::~TextureCache()
{
DeleteShaders();
}
void TextureCache::DisableStage(unsigned int stage)
{
}
void TextureCache::SetStage()
{
// -1 is the initial value as we don't know which texture should be bound
if (s_ActiveTexture != (u32)-1)
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
}
void TextureCache::CompileShaders()
{
const char *pColorMatrixProg =
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"uniform vec4 colmat[7];\n"
"in vec2 uv0;\n"
"in vec3 f_uv0;\n"
"out vec4 ocol0;\n"
"\n"
"void main(){\n"
" vec4 texcol = texture(samp9, uv0);\n"
" vec4 texcol = texture(samp9, f_uv0);\n"
" texcol = round(texcol * colmat[5]) * colmat[6];\n"
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n"
"}\n";
const char *pDepthMatrixProg =
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"uniform vec4 colmat[5];\n"
"in vec2 uv0;\n"
"in vec3 f_uv0;\n"
"out vec4 ocol0;\n"
"\n"
"void main(){\n"
" vec4 texcol = texture(samp9, uv0);\n"
" vec4 texcol = texture(samp9, vec3(f_uv0.xy, %s));\n"
// 255.99998474121 = 16777215/16777216*256
" float workspace = texcol.x * 255.99998474121;\n"
@ -363,18 +388,41 @@ TextureCache::TextureCache()
"}\n";
const char *VProgram =
"out vec2 uv0;\n"
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"out vec3 %s_uv0;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"uniform vec4 copy_position;\n" // left, top, right, bottom
"void main()\n"
"{\n"
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
" uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0));\n"
" %s_uv0 = vec3(mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy), 0.0);\n"
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
"}\n";
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, VProgram, pColorMatrixProg);
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, VProgram, pDepthMatrixProg);
const char *GProgram = (g_ActiveConfig.iStereoMode > 0) ?
"layout(triangles) in;\n"
"layout(triangle_strip, max_vertices = 6) out;\n"
"in vec3 v_uv0[3];\n"
"out vec3 f_uv0;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"void main()\n"
"{\n"
" int layers = textureSize(samp9, 0).z;\n"
" for (int layer = 0; layer < layers; ++layer) {\n"
" for (int i = 0; i < 3; ++i) {\n"
" f_uv0 = vec3(v_uv0[i].xy, layer);\n"
" gl_Position = gl_in[i].gl_Position;\n"
" gl_Layer = layer;\n"
" EmitVertex();\n"
" }\n"
" EndPrimitive();\n"
" }\n"
"}\n" : nullptr;
const char* prefix = (GProgram == nullptr) ? "f" : "v";
const char* depth_layer = (g_ActiveConfig.bStereoMonoEFBDepth) ? "0" : "f_uv0.z";
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), pColorMatrixProg, GProgram);
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), StringFromFormat(pDepthMatrixProg, depth_layer).c_str(), GProgram);
s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat");
s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat");
@ -383,28 +431,12 @@ TextureCache::TextureCache()
s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position");
s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position");
s_ActiveTexture = -1;
for (auto& gtex : s_Textures)
gtex = -1;
}
TextureCache::~TextureCache()
void TextureCache::DeleteShaders()
{
s_ColorMatrixProgram.Destroy();
s_DepthMatrixProgram.Destroy();
}
void TextureCache::DisableStage(unsigned int stage)
{
}
void TextureCache::SetStage ()
{
// -1 is the initial value as we don't know which texture should be bound
if (s_ActiveTexture != (u32)-1)
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
}
}

View File

@ -57,6 +57,9 @@ private:
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) override;
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) override;
void CompileShaders() override;
void DeleteShaders() override;
};
bool SaveTexture(const std::string& filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level);

View File

@ -72,21 +72,21 @@ static void CreatePrograms()
const char *VProgramRgbToYuyv =
"out vec2 uv0;\n"
"uniform vec4 copy_position;\n" // left, top, right, bottom
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"void main()\n"
"{\n"
" vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n"
" gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n"
" uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0));\n"
" uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy);\n"
"}\n";
const char *FProgramRgbToYuyv =
"SAMPLER_BINDING(9) uniform sampler2D samp9;\n"
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"void main()\n"
"{\n"
" vec3 c0 = texture(samp9, (uv0 - dFdx(uv0) * 0.25)).rgb;\n"
" vec3 c1 = texture(samp9, (uv0 + dFdx(uv0) * 0.25)).rgb;\n"
" vec3 c0 = texture(samp9, vec3(uv0 - dFdx(uv0) * 0.25, 0.0)).rgb;\n"
" vec3 c1 = texture(samp9, vec3(uv0 + dFdx(uv0) * 0.25, 0.0)).rgb;\n"
" vec3 c01 = (c0 + c1) * 0.5;\n"
" vec3 y_const = vec3(0.257,0.504,0.098);\n"
" vec3 u_const = vec3(-0.148,-0.291,0.439);\n"
@ -224,17 +224,17 @@ static void EncodeToRamUsingShader(GLuint srcTexture,
// set source texture
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, srcTexture);
glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);
if (linearFilter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);
@ -365,7 +365,7 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur
// switch to texture converter frame buffer
// attach destTexture as color destination
FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destTexture, 0);
// activate source texture
// set srcAddr as data for source texture

View File

@ -138,6 +138,7 @@ static void InitBackendInfo()
//g_Config.backend_info.bSupportsDualSourceBlend = true; // is gpu dependent and must be set in renderer
//g_Config.backend_info.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer
g_Config.backend_info.bSupportsOversizedViewports = true;
g_Config.backend_info.bSupportsStereoscopy = true;
g_Config.backend_info.Adapters.clear();

View File

@ -9,6 +9,7 @@ set(SRCS BoundingBox.cpp
Fifo.cpp
FPSCounter.cpp
FramebufferManagerBase.cpp
GeometryShaderGen.cpp
HiresTextures.cpp
ImageWrite.cpp
IndexGenerator.cpp

View File

@ -43,5 +43,6 @@ struct VertexShaderConstants
float4 normalmatrices[32];
float4 posttransformmatrices[64];
float4 depthparams;
float4 stereoparams;
};

View File

@ -12,6 +12,8 @@ const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[MAX_VIRTUAL_X
unsigned int FramebufferManagerBase::s_last_xfb_width = 1;
unsigned int FramebufferManagerBase::s_last_xfb_height = 1;
unsigned int FramebufferManagerBase::m_EFBLayers = 1;
FramebufferManagerBase::FramebufferManagerBase()
{
m_realXFBSource = nullptr;

View File

@ -55,6 +55,8 @@ public:
static int ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width);
static int ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height);
static int GetEFBLayers() { return m_EFBLayers; }
protected:
struct VirtualXFB
{
@ -70,6 +72,8 @@ protected:
typedef std::list<VirtualXFB> VirtualXFBListType;
static unsigned int m_EFBLayers;
private:
virtual XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height) = 0;
// TODO: figure out why OGL is different for this guy

View File

@ -0,0 +1,134 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <cmath>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif
#include "VideoCommon/GeometryShaderGen.h"
#include "VideoCommon/LightingShaderGen.h"
#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VideoConfig.h"
static char text[16384];
template<class T>
static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiType)
{
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
geometry_shader_uid_data dummy_data;
geometry_shader_uid_data* uid_data = out.template GetUidData<geometry_shader_uid_data>();
if (uid_data == nullptr)
uid_data = &dummy_data;
out.SetBuffer(text);
const bool is_writing_shadercode = (out.GetBuffer() != nullptr);
#ifndef ANDROID
locale_t locale;
locale_t old_locale;
if (is_writing_shadercode)
{
locale = newlocale(LC_NUMERIC_MASK, "C", nullptr); // New locale for compilation
old_locale = uselocale(locale); // Apply the locale for this thread
}
#endif
if (is_writing_shadercode)
text[sizeof(text) - 1] = 0x7C; // canary
out.Write("//Geometry Shader for 3D stereoscopy\n");
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (ApiType == API_OPENGL)
{
// Insert layout parameters
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
out.Write("layout(triangles, invocations = %d) in;\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
else
out.Write("layout(triangles) in;\n");
out.Write("layout(triangle_strip, max_vertices = %d) out;\n", g_ActiveConfig.backend_info.bSupportsGSInstancing ? 3 : 6);
}
out.Write("%s", s_lighting_struct);
// uniforms
if (ApiType == API_OPENGL)
out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : "");
else
out.Write("cbuffer VSBlock {\n");
out.Write(s_shader_uniforms);
out.Write("};\n");
uid_data->numTexGens = xfmem.numTexGen.numTexGens;
uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting;
GenerateVSOutputStruct(out, ApiType);
out.Write("centroid in VS_OUTPUT o[3];\n");
out.Write("centroid out VS_OUTPUT f;\n");
out.Write("flat out int layer;\n");
out.Write("void main()\n{\n");
// If the GPU supports invocation we don't need a for loop and can simply use the
// invocation identifier to determine which layer we're rendering.
if (g_ActiveConfig.backend_info.bSupportsGSInstancing)
out.Write("\tint l = gl_InvocationID;\n");
else
out.Write("\tfor (int l = 0; l < %d; ++l) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1);
out.Write("\tfor (int i = 0; i < 3; ++i) {\n");
out.Write("\t\tlayer = l;\n");
out.Write("\t\tgl_Layer = l;\n");
out.Write("\t\tf = o[i];\n");
out.Write("\t\tfloat4 pos = o[i].pos;\n");
if (g_ActiveConfig.iStereoMode > 0)
{
// For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional
// to the depth of the vertex. We retrieve the depth value from the w-component of the projected
// vertex which contains the negated z-component of the original vertex.
// For negative parallax (out-of-screen effects) we subtract a convergence value from
// the depth value. This results in objects at a distance smaller than the convergence
// distance to seemingly appear in front of the screen.
// This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide"
out.Write("\t\tf.clipPos.x = o[i].clipPos.x + " I_STEREOPARAMS"[l] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n");
out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[l] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n");
}
out.Write("\t\tf.pos.x = pos.x;\n");
out.Write("\t\tgl_Position = pos;\n");
out.Write("\t\tEmitVertex();\n");
out.Write("\t}\n");
out.Write("\tEndPrimitive();\n");
if (!g_ActiveConfig.backend_info.bSupportsGSInstancing)
out.Write("\t}\n");
out.Write("}\n");
if (is_writing_shadercode)
{
if (text[sizeof(text) - 1] != 0x7C)
PanicAlert("GeometryShader generator - buffer too small, canary has been eaten!");
#ifndef ANDROID
uselocale(old_locale); // restore locale
freelocale(locale);
#endif
}
}
void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType)
{
GenerateGeometryShader<GeometryShaderUid>(object, components, ApiType);
}
void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType)
{
GenerateGeometryShader<ShaderCode>(object, components, ApiType);
}

View File

@ -0,0 +1,26 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VideoCommon.h"
#pragma pack(1)
struct geometry_shader_uid_data
{
u32 NumValues() const { return sizeof(geometry_shader_uid_data); }
u32 stereo : 1;
u32 numTexGens : 4;
u32 pixel_lighting : 1;
};
#pragma pack()
typedef ShaderUid<geometry_shader_uid_data> GeometryShaderUid;
void GenerateGeometryShaderCode(ShaderCode& object, u32 components, API_TYPE ApiType);
void GetGeometryShaderUid(GeometryShaderUid& object, u32 components, API_TYPE ApiType);

View File

@ -16,6 +16,7 @@
#include "VideoCommon/LightingShaderGen.h"
#include "VideoCommon/NativeVertexFormat.h"
#include "VideoCommon/PixelShaderGen.h"
#include "VideoCommon/VertexShaderGen.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h" // for texture projection mode
@ -206,7 +207,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
{
// Declare samplers
for (int i = 0; i < 8; ++i)
out.Write("SAMPLER_BINDING(%d) uniform sampler2D samp%d;\n", i, i);
out.Write("SAMPLER_BINDING(%d) uniform sampler2DArray samp%d;\n", i, i);
}
else // D3D
{
@ -253,17 +254,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
{
out.Write("cbuffer VSBlock : register(b1) {\n");
}
out.Write(
"\tfloat4 " I_POSNORMALMATRIX"[6];\n"
"\tfloat4 " I_PROJECTION"[4];\n"
"\tint4 " I_MATERIALS"[4];\n"
"\tLight " I_LIGHTS"[8];\n"
"\tfloat4 " I_TEXMATRICES"[24];\n"
"\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_NORMALMATRICES"[32];\n"
"\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_DEPTHPARAMS";\n"
"};\n");
out.Write(s_shader_uniforms);
out.Write("};\n");
}
if (g_ActiveConfig.backend_info.bSupportsBBox)
@ -275,6 +267,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
);
}
GenerateVSOutputStruct(out, ApiType);
const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED);
const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z);
@ -325,22 +319,52 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
// As a workaround, we interpolate at the centroid of the coveraged pixel, which
// is always inside the primitive.
// Without MSAA, this flag is defined to have no effect.
out.Write("centroid in float4 colors_02;\n");
out.Write("centroid in float4 colors_12;\n");
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
for (unsigned int i = 0; i < numTexgen; ++i)
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (g_ActiveConfig.iStereoMode > 0)
{
out.Write("centroid in float3 uv%d;\n", i);
out.Write("centroid in VS_OUTPUT f;\n");
out.Write("flat in int layer;\n");
}
out.Write("centroid in float4 clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
else
{
out.Write("centroid in float4 Normal;\n");
out.Write("centroid in float4 colors_02;\n");
out.Write("centroid in float4 colors_12;\n");
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
for (unsigned int i = 0; i < numTexgen; ++i)
{
out.Write("centroid in float3 uv%d;\n", i);
}
out.Write("centroid in float4 clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
{
out.Write("centroid in float4 Normal;\n");
}
}
out.Write("void main()\n{\n");
if (g_ActiveConfig.iStereoMode > 0)
{
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
for (unsigned int i = 0; i < numTexgen; ++i)
{
out.Write("\tfloat3 uv%d = f.tex%d;\n", i, i);
}
out.Write("\tfloat4 clipPos = f.clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
{
out.Write("\tfloat4 Normal = f.Normal;\n");
}
}
// On Mali, global variables must be initialized as constants.
// This is why we initialize these variables locally instead.
out.Write("\tfloat4 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_0" : "colors_02");
out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_1" : "colors_12");
out.Write("\tfloat4 rawpos = gl_FragCoord;\n");
}
else // D3D
@ -370,14 +394,6 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
"\tint2 wrappedcoord=int2(0,0), tempcoord=int2(0,0);\n"
"\tint4 tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0,0);\n\n"); // tev combiner inputs
if (ApiType == API_OPENGL)
{
// On Mali, global variables must be initialized as constants.
// This is why we initialize these variables locally instead.
out.Write("\tfloat4 colors_0 = colors_02;\n");
out.Write("\tfloat4 colors_1 = colors_12;\n");
}
if (g_ActiveConfig.bEnablePixelLighting)
{
out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n");
@ -931,7 +947,7 @@ static inline void SampleTexture(T& out, const char *texcoords, const char *texs
if (ApiType == API_D3D)
out.Write("iround(255.0 * Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy)).%s;\n", texmap,texmap, texcoords, texmap, texswap);
else
out.Write("iround(255.0 * texture(samp%d,%s.xy * " I_TEXDIMS"[%d].xy)).%s;\n", texmap, texcoords, texmap, texswap);
out.Write("iround(255.0 * texture(samp%d, float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap);
}
static const char *tevAlphaFuncsTable[] =

View File

@ -44,7 +44,7 @@ struct pixel_shader_uid_data
u32 dstAlphaMode : 2;
u32 Pretest : 2;
u32 nIndirectStagesUsed : 4;
u32 pad0 : 1;
u32 stereo : 1;
u32 genMode_numtexgens : 4;
u32 genMode_numtevstages : 4;

View File

@ -91,7 +91,7 @@ public:
// Should be implemented by the backends for backend specific code
virtual void BlitFromTexture(TargetRectangle src, TargetRectangle dst,
int src_texture, int src_width, int src_height) = 0;
int src_texture, int src_width, int src_height, int layer = 0) = 0;
virtual void ApplyShader() = 0;
protected:

View File

@ -240,6 +240,42 @@ bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int
return false;
}
void Renderer::ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc)
{
// Resize target to half its original size
TargetRectangle drawRc = rc;
if (g_ActiveConfig.iStereoMode == STEREO_TAB)
{
// The height may be negative due to flipped rectangles
int height = rc.bottom - rc.top;
drawRc.top += height / 4;
drawRc.bottom -= height / 4;
}
else
{
int width = rc.right - rc.left;
drawRc.left += width / 4;
drawRc.right -= width / 4;
}
// Create two target rectangle offset to the sides of the backbuffer
leftRc = drawRc, rightRc = drawRc;
if (g_ActiveConfig.iStereoMode == STEREO_TAB)
{
leftRc.top -= s_backbuffer_height / 4;
leftRc.bottom -= s_backbuffer_height / 4;
rightRc.top += s_backbuffer_height / 4;
rightRc.bottom += s_backbuffer_height / 4;
}
else
{
leftRc.left -= s_backbuffer_width / 4;
leftRc.right -= s_backbuffer_width / 4;
rightRc.left += s_backbuffer_width / 4;
rightRc.right += s_backbuffer_width / 4;
}
}
void Renderer::SetScreenshot(const std::string& filename)
{
std::lock_guard<std::mutex> lk(s_criticalScreenshot);

View File

@ -83,6 +83,8 @@ public:
static const TargetRectangle& GetTargetRectangle() { return target_rc; }
static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height);
// Use this to convert a single target rectangle to two stereo rectangles
static void ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc, TargetRectangle& rightRc);
// Use this to upscale native EFB coordinates to IDEAL internal resolution
static int EFBToScaledX(int x);

View File

@ -239,3 +239,16 @@ private:
#define I_NORMALMATRICES "cnmtx"
#define I_POSTTRANSFORMMATRICES "cpostmtx"
#define I_DEPTHPARAMS "cDepth" // farZ, zRange
#define I_STEREOPARAMS "cstereo"
static const char s_shader_uniforms[] =
"\tfloat4 " I_POSNORMALMATRIX"[6];\n"
"\tfloat4 " I_PROJECTION"[4];\n"
"\tint4 " I_MATERIALS"[4];\n"
"\tLight " I_LIGHTS"[8];\n"
"\tfloat4 " I_TEXMATRICES"[24];\n"
"\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_NORMALMATRICES"[32];\n"
"\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_DEPTHPARAMS";\n"
"\tfloat4 " I_STEREOPARAMS";\n";

View File

@ -115,6 +115,13 @@ void TextureCache::OnConfigChanged(VideoConfig& config)
{
g_texture_cache->ClearRenderTargets();
}
if ((config.iStereoMode > 0) != backup_config.s_stereo_3d ||
config.bStereoMonoEFBDepth != backup_config.s_mono_efb_depth)
{
g_texture_cache->DeleteShaders();
g_texture_cache->CompileShaders();
}
}
backup_config.s_colorsamples = config.iSafeTextureCache_ColorSamples;
@ -126,6 +133,8 @@ void TextureCache::OnConfigChanged(VideoConfig& config)
backup_config.s_texfmt_overlay_center = config.bTexFmtOverlayCenter;
backup_config.s_hires_textures = config.bHiresTextures;
backup_config.s_copy_cache_enable = config.bEFBCopyCacheEnable;
backup_config.s_stereo_3d = config.iStereoMode > 0;
backup_config.s_mono_efb_depth = config.bStereoMonoEFBDepth;
}
void TextureCache::Cleanup()
@ -444,14 +453,15 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
//
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches...
if ((entry->type == TCET_NORMAL &&
if (((entry->type == TCET_NORMAL &&
width == entry->virtual_width &&
height == entry->virtual_height &&
full_format == entry->format &&
entry->num_mipmaps > maxlevel) ||
(entry->type == TCET_EC_DYNAMIC &&
entry->native_width == width &&
entry->native_height == height))
entry->native_height == height)) &&
entry->num_layers == 1)
{
// reuse the texture
}
@ -519,6 +529,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
// But that will currently make the above "existing entry" tests fail as "texLevels" is not calculated until after.
// Currently, we might try to reuse a texture which appears to have more levels than actual, maybe..
entry->num_mipmaps = maxlevel + 1;
entry->num_layers = 1;
entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
@ -529,7 +540,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
entry->Load(width, height, expandedWidth, 0);
}
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps);
entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps, entry->num_layers);
entry->SetDimensions(nativeW, nativeH, width, height);
entry->hash = tex_hash;
@ -886,12 +897,12 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
TCacheEntryBase *entry = textures[dstAddr];
if (entry)
{
if (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h)
if (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h && entry->num_layers == FramebufferManagerBase::GetEFBLayers())
{
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
else if (!(entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h))
else if (!(entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h && entry->num_layers == FramebufferManagerBase::GetEFBLayers()))
{
if (entry->type == TCET_EC_VRAM)
{
@ -914,7 +925,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
textures[dstAddr] = entry = AllocateRenderTarget(scaled_tex_w, scaled_tex_h);
// TODO: Using the wrong dstFormat, dumb...
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1);
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1, FramebufferManagerBase::GetEFBLayers());
entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
entry->SetHashes(TEXHASH_INVALID);
entry->type = TCET_EC_VRAM;

View File

@ -39,6 +39,7 @@ public:
enum TexCacheEntryType type;
unsigned int num_mipmaps;
unsigned int num_layers;
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
unsigned int virtual_width, virtual_height; // Texture dimensions from OUR point of view - for hires textures or scaled EFB copies
@ -46,12 +47,13 @@ public:
int frameCount;
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps)
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format, unsigned int _num_mipmaps, unsigned int _num_layers)
{
addr = _addr;
size_in_bytes = _size;
format = _format;
num_mipmaps = _num_mipmaps;
num_layers = _num_layers;
}
void SetDimensions(unsigned int _native_width, unsigned int _native_height, unsigned int _virtual_width, unsigned int _virtual_height)
@ -101,6 +103,9 @@ public:
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0;
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h) = 0;
virtual void CompileShaders() = 0; // currently only implemented by OGL
virtual void DeleteShaders() = 0; // currently only implemented by OGL
static TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, unsigned int height,
int format, unsigned int tlutaddr, int tlutfmt, bool use_mipmaps, unsigned int maxlevel, bool from_tmem);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, PEControl::PixelFormat srcFormat,
@ -140,6 +145,8 @@ private:
bool s_texfmt_overlay_center;
bool s_hires_textures;
bool s_copy_cache_enable;
bool s_stereo_3d;
bool s_mono_efb_depth;
} backup_config;
};

View File

@ -70,7 +70,7 @@ static void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType)
if (ApiType == API_OPENGL)
{
WRITE(p, "#define samp0 samp9\n");
WRITE(p, "SAMPLER_BINDING(9) uniform sampler2D samp0;\n");
WRITE(p, "SAMPLER_BINDING(9) uniform sampler2DArray samp0;\n");
WRITE(p, " out vec4 ocol0;\n");
WRITE(p, "void main()\n");
@ -120,7 +120,7 @@ static void WriteSwizzler(char*& p, u32 format, API_TYPE ApiType)
static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset, API_TYPE ApiType)
{
WRITE(p, " %s = texture(samp0, uv0 + float2(%d, 0) * sample_offset).%s;\n",
WRITE(p, " %s = texture(samp0, float3(uv0 + float2(%d, 0) * sample_offset, 0.0)).%s;\n",
dest, xoffset, colorComp
);
}

View File

@ -89,17 +89,8 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
out.Write("layout(std140%s) uniform VSBlock {\n", g_ActiveConfig.backend_info.bSupportsBindingLayout ? ", binding = 2" : "");
else
out.Write("cbuffer VSBlock {\n");
out.Write(
"\tfloat4 " I_POSNORMALMATRIX"[6];\n"
"\tfloat4 " I_PROJECTION"[4];\n"
"\tint4 " I_MATERIALS"[4];\n"
"\tLight " I_LIGHTS"[8];\n"
"\tfloat4 " I_TEXMATRICES"[24];\n"
"\tfloat4 " I_TRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_NORMALMATRICES"[32];\n"
"\tfloat4 " I_POSTTRANSFORMMATRICES"[64];\n"
"\tfloat4 " I_DEPTHPARAMS";\n"
"};\n");
out.Write(s_shader_uniforms);
out.Write("};\n");
GenerateVSOutputStruct(out, api_type);
@ -131,22 +122,33 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
out.Write("in float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i, SHADER_TEXTURE0_ATTRIB + i);
}
// Let's set up attributes
for (size_t i = 0; i < 8; ++i)
uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (g_ActiveConfig.iStereoMode > 0)
{
if (i < xfmem.numTexGen.numTexGens)
{
out.Write("centroid out float3 uv%d;\n", i);
}
out.Write("centroid out VS_OUTPUT o;\n");
}
out.Write("centroid out float4 clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
out.Write("centroid out float4 Normal;\n");
else
{
// Let's set up attributes
for (size_t i = 0; i < 8; ++i)
{
if (i < xfmem.numTexGen.numTexGens)
{
out.Write("centroid out float3 uv%d;\n", i);
}
}
out.Write("centroid out float4 colors_02;\n");
out.Write("centroid out float4 colors_12;\n");
out.Write("centroid out float4 clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
out.Write("centroid out float4 Normal;\n");
out.Write("centroid out float4 colors_02;\n");
out.Write("centroid out float4 colors_12;\n");
}
out.Write("void main()\n{\n");
if (g_ActiveConfig.iStereoMode <= 0)
out.Write("VS_OUTPUT o;\n");
}
else // D3D
{
@ -172,8 +174,9 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
if (components & VB_HAS_POSMTXIDX)
out.Write(" int posmtx : BLENDINDICES,\n");
out.Write(" float4 rawpos : POSITION) {\n");
out.Write("VS_OUTPUT o;\n");
}
out.Write("VS_OUTPUT o;\n");
// transforms
if (components & VB_HAS_POSMTXIDX)
@ -431,27 +434,32 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
if (api_type == API_OPENGL)
{
// Bit ugly here
// TODO: Make pretty
// Will look better when we bind uniforms in GLSL 1.3
// clipPos/w needs to be done in pixel shader, not here
if (g_ActiveConfig.iStereoMode <= 0)
{
// Bit ugly here
// TODO: Make pretty
// Will look better when we bind uniforms in GLSL 1.3
// clipPos/w needs to be done in pixel shader, not here
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
out.Write(" uv%d.xyz = o.tex%d;\n", i, i);
out.Write(" clipPos = o.clipPos;\n");
for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i)
out.Write("uv%d.xyz = o.tex%d;\n", i, i);
if (g_ActiveConfig.bEnablePixelLighting)
out.Write(" Normal = o.Normal;\n");
out.Write("clipPos = o.clipPos;\n");
if (g_ActiveConfig.bEnablePixelLighting)
out.Write("Normal = o.Normal;\n");
out.Write("colors_02 = o.colors_0;\n");
out.Write("colors_12 = o.colors_1;\n");
}
out.Write("colors_02 = o.colors_0;\n");
out.Write("colors_12 = o.colors_1;\n");
out.Write("gl_Position = o.pos;\n");
out.Write("}\n");
}
else // D3D
{
out.Write("return o;\n}\n");
out.Write("return o;\n");
}
out.Write("}\n");
if (is_writing_shadercode)
{
@ -475,7 +483,12 @@ void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE
GenerateVertexShader<VertexShaderCode>(object, components, api_type);
}
void GenerateVSOutputStructForGS(ShaderCode& object, API_TYPE api_type)
void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type)
{
GenerateVSOutputStruct<ShaderCode>(object, api_type);
}
void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type)
{
// Ignore unknown types
}

View File

@ -38,7 +38,7 @@ struct vertex_shader_uid_data
u32 numColorChans : 2;
u32 dualTexTrans_enabled : 1;
u32 pixel_lighting : 1;
u32 pad0 : 1;
u32 stereo : 1;
u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide
struct {
@ -64,4 +64,5 @@ typedef ShaderCode VertexShaderCode; // TODO: Obsolete..
void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type);
void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE api_type);
void GenerateVSOutputStructForGS(ShaderCode& object, API_TYPE api_type);
void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type);
void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type);

View File

@ -489,7 +489,7 @@ void VertexShaderManager::SetConstants()
PRIM_LOG("Projection: %f %f %f %f %f %f\n", rawProjection[0], rawProjection[1], rawProjection[2], rawProjection[3], rawProjection[4], rawProjection[5]);
if ((g_ActiveConfig.bFreeLook || g_ActiveConfig.bAnaglyphStereo ) && xfmem.projection.type == GX_PERSPECTIVE)
if (g_ActiveConfig.bFreeLook && xfmem.projection.type == GX_PERSPECTIVE)
{
Matrix44 mtxA;
Matrix44 mtxB;
@ -512,6 +512,19 @@ void VertexShaderManager::SetConstants()
Matrix44::Multiply(s_viewportCorrection, projMtx, correctedMtx);
memcpy(constants.projection, correctedMtx.data, 4*16);
}
if (g_ActiveConfig.iStereoMode > 0 && xfmem.projection.type == GX_PERSPECTIVE)
{
float offset = (g_ActiveConfig.iStereoSeparation / 1000.0f) * (g_ActiveConfig.iStereoSeparationPercent / 100.0f);
constants.stereoparams[0] = (g_ActiveConfig.bStereoSwapEyes) ? offset : -offset;
constants.stereoparams[1] = (g_ActiveConfig.bStereoSwapEyes) ? -offset : offset;
constants.stereoparams[2] = (g_ActiveConfig.iStereoConvergence / 10.0f) * (g_ActiveConfig.iStereoConvergencePercent / 100.0f);
}
else
{
constants.stereoparams[0] = constants.stereoparams[1] = 0;
}
dirty = true;
}
}

View File

@ -60,6 +60,7 @@
<ClCompile Include="PostProcessing.cpp" />
<ClCompile Include="RenderBase.cpp" />
<ClCompile Include="Statistics.cpp" />
<ClCompile Include="GeometryShaderGen.cpp" />
<ClCompile Include="TextureCacheBase.cpp" />
<ClCompile Include="TextureConversionShader.cpp" />
<ClCompile Include="VertexLoader.cpp" />
@ -110,6 +111,7 @@
<ClInclude Include="RenderBase.h" />
<ClInclude Include="ShaderGenCommon.h" />
<ClInclude Include="Statistics.h" />
<ClInclude Include="GeometryShaderGen.h" />
<ClInclude Include="TextureCacheBase.h" />
<ClInclude Include="TextureConversionShader.h" />
<ClInclude Include="TextureDecoder.h" />

View File

@ -143,6 +143,9 @@
<ClCompile Include="BoundingBox.cpp">
<Filter>Util</Filter>
</ClCompile>
<ClCompile Include="GeometryShaderGen.cpp">
<Filter>Shader Generators</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CommandProcessor.h" />
@ -275,6 +278,9 @@
<ClInclude Include="BoundingBox.h">
<Filter>Util</Filter>
</ClInclude>
<ClInclude Include="GeometryShaderGen.h">
<Filter>Shader Generators</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View File

@ -38,6 +38,11 @@ VideoConfig::VideoConfig()
backend_info.APIType = API_NONE;
backend_info.bUseMinimalMipCount = false;
backend_info.bSupportsExclusiveFullscreen = false;
// Game-specific stereoscopy settings
bStereoMonoEFBDepth = false;
iStereoSeparationPercent = 100;
iStereoConvergencePercent = 100;
}
void VideoConfig::Load(const std::string& ini_file)
@ -66,9 +71,6 @@ void VideoConfig::Load(const std::string& ini_file)
settings->Get("DumpEFBTarget", &bDumpEFBTarget, 0);
settings->Get("FreeLook", &bFreeLook, 0);
settings->Get("UseFFV1", &bUseFFV1, 0);
settings->Get("AnaglyphStereo", &bAnaglyphStereo, false);
settings->Get("AnaglyphStereoSeparation", &iAnaglyphStereoSeparation, 200);
settings->Get("AnaglyphFocalAngle", &iAnaglyphFocalAngle, 0);
settings->Get("EnablePixelLighting", &bEnablePixelLighting, 0);
settings->Get("FastDepthCalc", &bFastDepthCalc, true);
settings->Get("MSAA", &iMultisampleMode, 0);
@ -85,6 +87,10 @@ void VideoConfig::Load(const std::string& ini_file)
enhancements->Get("ForceFiltering", &bForceFiltering, 0);
enhancements->Get("MaxAnisotropy", &iMaxAnisotropy, 0); // NOTE - this is x in (1 << x)
enhancements->Get("PostProcessingShader", &sPostProcessingShader, "");
enhancements->Get("StereoMode", &iStereoMode, 0);
enhancements->Get("StereoSeparation", &iStereoSeparation, 20);
enhancements->Get("StereoConvergence", &iStereoConvergence, 20);
enhancements->Get("StereoSwapEyes", &bStereoSwapEyes, false);
IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks");
hacks->Get("EFBAccessEnable", &bEFBAccessEnable, true);
@ -140,9 +146,6 @@ void VideoConfig::GameIniLoad()
CHECK_SETTING("Video_Settings", "UseRealXFB", bUseRealXFB);
CHECK_SETTING("Video_Settings", "SafeTextureCacheColorSamples", iSafeTextureCache_ColorSamples);
CHECK_SETTING("Video_Settings", "HiresTextures", bHiresTextures);
CHECK_SETTING("Video_Settings", "AnaglyphStereo", bAnaglyphStereo);
CHECK_SETTING("Video_Settings", "AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
CHECK_SETTING("Video_Settings", "AnaglyphFocalAngle", iAnaglyphFocalAngle);
CHECK_SETTING("Video_Settings", "EnablePixelLighting", bEnablePixelLighting);
CHECK_SETTING("Video_Settings", "FastDepthCalc", bFastDepthCalc);
CHECK_SETTING("Video_Settings", "MSAA", iMultisampleMode);
@ -179,6 +182,14 @@ void VideoConfig::GameIniLoad()
CHECK_SETTING("Video_Enhancements", "ForceFiltering", bForceFiltering);
CHECK_SETTING("Video_Enhancements", "MaxAnisotropy", iMaxAnisotropy); // NOTE - this is x in (1 << x)
CHECK_SETTING("Video_Enhancements", "PostProcessingShader", sPostProcessingShader);
CHECK_SETTING("Video_Enhancements", "StereoMode", iStereoMode);
CHECK_SETTING("Video_Enhancements", "StereoSeparation", iStereoSeparation);
CHECK_SETTING("Video_Enhancements", "StereoConvergence", iStereoConvergence);
CHECK_SETTING("Video_Enhancements", "StereoSwapEyes", bStereoSwapEyes);
CHECK_SETTING("Video_Stereoscopy", "StereoMonoEFBDepth", bStereoMonoEFBDepth);
CHECK_SETTING("Video_Stereoscopy", "StereoSeparationPercent", iStereoSeparationPercent);
CHECK_SETTING("Video_Stereoscopy", "StereoConvergencePercent", iStereoConvergencePercent);
CHECK_SETTING("Video_Hacks", "EFBAccessEnable", bEFBAccessEnable);
CHECK_SETTING("Video_Hacks", "EFBCopyEnable", bEFBCopyEnable);
@ -203,6 +214,7 @@ void VideoConfig::VerifyValidity()
// TODO: Check iMaxAnisotropy value
if (iAdapter < 0 || iAdapter > ((int)backend_info.Adapters.size() - 1)) iAdapter = 0;
if (iMultisampleMode < 0 || iMultisampleMode >= (int)backend_info.AAModes.size()) iMultisampleMode = 0;
if (!backend_info.bSupportsStereoscopy) iStereoMode = 0;
}
void VideoConfig::Save(const std::string& ini_file)
@ -230,9 +242,6 @@ void VideoConfig::Save(const std::string& ini_file)
settings->Set("DumpEFBTarget", bDumpEFBTarget);
settings->Set("FreeLook", bFreeLook);
settings->Set("UseFFV1", bUseFFV1);
settings->Set("AnaglyphStereo", bAnaglyphStereo);
settings->Set("AnaglyphStereoSeparation", iAnaglyphStereoSeparation);
settings->Set("AnaglyphFocalAngle", iAnaglyphFocalAngle);
settings->Set("EnablePixelLighting", bEnablePixelLighting);
settings->Set("FastDepthCalc", bFastDepthCalc);
settings->Set("ShowEFBCopyRegions", bShowEFBCopyRegions);
@ -250,6 +259,10 @@ void VideoConfig::Save(const std::string& ini_file)
enhancements->Set("ForceFiltering", bForceFiltering);
enhancements->Set("MaxAnisotropy", iMaxAnisotropy);
enhancements->Set("PostProcessingShader", sPostProcessingShader);
enhancements->Set("StereoMode", iStereoMode);
enhancements->Set("StereoSeparation", iStereoSeparation);
enhancements->Set("StereoConvergence", iStereoConvergence);
enhancements->Set("StereoSwapEyes", bStereoSwapEyes);
IniFile::Section* hacks = iniFile.GetOrCreateSection("Hacks");
hacks->Set("EFBAccessEnable", bEFBAccessEnable);

View File

@ -44,6 +44,14 @@ enum EFBScale
SCALE_4X,
};
enum StereoMode
{
STEREO_OFF = 0,
STEREO_SBS,
STEREO_TAB,
STEREO_ANAGLYPH
};
// NEVER inherit from this class.
struct VideoConfig final
{
@ -71,6 +79,10 @@ struct VideoConfig final
bool bForceFiltering;
int iMaxAnisotropy;
std::string sPostProcessingShader;
int iStereoMode;
int iStereoSeparation;
int iStereoConvergence;
bool bStereoSwapEyes;
// Information
bool bShowFPS;
@ -92,9 +104,6 @@ struct VideoConfig final
bool bDumpEFBTarget;
bool bUseFFV1;
bool bFreeLook;
bool bAnaglyphStereo;
int iAnaglyphStereoSeparation;
int iAnaglyphFocalAngle;
bool bBorderlessFullscreen;
// Hacks
@ -115,6 +124,11 @@ struct VideoConfig final
int iLog; // CONF_ bits
int iSaveTargetId; // TODO: Should be dropped
// Stereoscopy
bool bStereoMonoEFBDepth;
int iStereoSeparationPercent;
int iStereoConvergencePercent;
// D3D only config, mostly to be merged into the above
int iAdapter;
@ -136,9 +150,11 @@ struct VideoConfig final
bool bSupportsDualSourceBlend;
bool bSupportsPrimitiveRestart;
bool bSupportsOversizedViewports;
bool bSupportsStereoscopy;
bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon
bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon
bool bSupportsBBox;
bool bSupportsGSInstancing; // Needed by GeometryShaderGen, so must stay in VideoCommon
} backend_info;
// Utility