mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-26 15:49:50 -06:00
Merge 'master' into shader-uids-awesome.
Conflicts: Source/Core/VideoCommon/Src/LightingShaderGen.cpp Source/Core/VideoCommon/Src/PixelShaderGen.cpp Source/Core/VideoCommon/Src/PixelShaderGen.h Source/Core/VideoCommon/Src/PixelShaderManager.cpp Source/Core/VideoCommon/Src/VertexShaderGen.cpp Source/Core/VideoCommon/Src/VertexShaderGen.h Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h
This commit is contained in:
@ -2,10 +2,14 @@ set(SRCS Src/FramebufferManager.cpp
|
||||
Src/GLUtil.cpp
|
||||
Src/main.cpp
|
||||
Src/NativeVertexFormat.cpp
|
||||
Src/PerfQuery.cpp
|
||||
Src/PixelShaderCache.cpp
|
||||
Src/PostProcessing.cpp
|
||||
Src/ProgramShaderCache.cpp
|
||||
Src/RasterFont.cpp
|
||||
Src/Render.cpp
|
||||
Src/SamplerCache.cpp
|
||||
Src/StreamBuffer.cpp
|
||||
Src/TextureCache.cpp
|
||||
Src/TextureConverter.cpp
|
||||
Src/VertexShaderCache.cpp
|
||||
@ -33,12 +37,6 @@ if(wxWidgets_FOUND)
|
||||
set(LIBS ${LIBS} ${wxWidgets_LIBRARIES})
|
||||
endif(wxWidgets_FOUND)
|
||||
|
||||
if(WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
set(LIBS ${LIBS} Cg CgGL)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/Externals/Cg/Cg.framework")
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(LIBS ${LIBS} clrun)
|
||||
endif()
|
||||
|
@ -121,8 +121,8 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -133,8 +133,8 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -147,8 +147,8 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -161,8 +161,8 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -175,8 +175,8 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -189,8 +189,8 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
<Lib />
|
||||
@ -200,10 +200,14 @@
|
||||
<ClCompile Include="Src\GLUtil.cpp" />
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="Src\PerfQuery.cpp" />
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp" />
|
||||
<ClCompile Include="Src\PostProcessing.cpp" />
|
||||
<ClCompile Include="Src\ProgramShaderCache.cpp" />
|
||||
<ClCompile Include="Src\RasterFont.cpp" />
|
||||
<ClCompile Include="Src\Render.cpp" />
|
||||
<ClCompile Include="Src\SamplerCache.cpp" />
|
||||
<ClCompile Include="Src\StreamBuffer.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
@ -222,15 +226,17 @@
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\GLUtil.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\PixelShaderCache.h" />
|
||||
<ClInclude Include="Src\PerfQuery.h" />
|
||||
<ClInclude Include="Src\PostProcessing.h" />
|
||||
<ClInclude Include="Src\ProgramShaderCache.h" />
|
||||
<ClInclude Include="Src\RasterFont.h" />
|
||||
<ClInclude Include="Src\Render.h" />
|
||||
<ClInclude Include="Src\SamplerCache.h" />
|
||||
<ClInclude Include="Src\StreamBuffer.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\TextureCache.h" />
|
||||
<ClInclude Include="Src\TextureConverter.h" />
|
||||
<ClInclude Include="Src\VertexManager.h" />
|
||||
<ClInclude Include="Src\VertexShaderCache.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -27,15 +27,24 @@
|
||||
<ClCompile Include="Src\PostProcessing.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\ProgramShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\StreamBuffer.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
@ -57,10 +66,10 @@
|
||||
<ClInclude Include="Src\FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PixelShaderCache.h">
|
||||
<ClInclude Include="Src\PostProcessing.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PostProcessing.h">
|
||||
<ClInclude Include="Src\ProgramShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Render.h">
|
||||
@ -69,7 +78,7 @@
|
||||
<ClInclude Include="Src\TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\VertexShaderCache.h">
|
||||
<ClInclude Include="Src\PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@ -90,4 +99,4 @@
|
||||
<UniqueIdentifier>{aaa16061-dca9-4155-be44-f77538e839fc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "Globals.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "TextureConverter.h"
|
||||
#include "Render.h"
|
||||
@ -25,8 +26,6 @@
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp. ugly.
|
||||
|
||||
int FramebufferManager::m_targetWidth;
|
||||
int FramebufferManager::m_targetHeight;
|
||||
int FramebufferManager::m_msaaSamples;
|
||||
@ -41,7 +40,7 @@ GLuint FramebufferManager::m_resolvedFramebuffer;
|
||||
GLuint FramebufferManager::m_resolvedColorTexture;
|
||||
GLuint FramebufferManager::m_resolvedDepthTexture;
|
||||
|
||||
GLuint FramebufferManager::m_xfbFramebuffer; // Only used in MSAA mode
|
||||
GLuint FramebufferManager::m_xfbFramebuffer;
|
||||
|
||||
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
|
||||
{
|
||||
@ -52,7 +51,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
m_resolvedColorTexture = 0;
|
||||
m_resolvedDepthTexture = 0;
|
||||
m_xfbFramebuffer = 0;
|
||||
|
||||
|
||||
m_targetWidth = targetWidth;
|
||||
m_targetHeight = targetHeight;
|
||||
|
||||
@ -72,7 +71,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
|
||||
// Create EFB target.
|
||||
|
||||
glGenFramebuffersEXT(1, &m_efbFramebuffer);
|
||||
glGenFramebuffers(1, &m_efbFramebuffer);
|
||||
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
@ -83,20 +82,20 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
m_efbColor = glObj[0];
|
||||
m_efbDepth = glObj[1];
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, m_efbColor);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, m_efbDepth);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
|
||||
|
||||
// Bind target textures to the EFB framebuffer.
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, m_efbColor, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, m_efbDepth, 0);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
}
|
||||
@ -109,67 +108,67 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
// Create EFB target renderbuffers.
|
||||
|
||||
GLuint glObj[2];
|
||||
glGenRenderbuffersEXT(2, glObj);
|
||||
glGenRenderbuffers(2, glObj);
|
||||
m_efbColor = glObj[0];
|
||||
m_efbDepth = glObj[1];
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_efbColor);
|
||||
if (m_msaaCoverageSamples)
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
else
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_efbDepth);
|
||||
if (m_msaaCoverageSamples)
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
else
|
||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
// Bind target renderbuffers to EFB framebuffer.
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_efbColor);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_efbDepth);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
// Create resolved targets for transferring multisampled EFB to texture.
|
||||
|
||||
glGenFramebuffersEXT(1, &m_resolvedFramebuffer);
|
||||
glGenFramebuffers(1, &m_resolvedFramebuffer);
|
||||
|
||||
glGenTextures(2, glObj);
|
||||
m_resolvedColorTexture = glObj[0];
|
||||
m_resolvedDepthTexture = glObj[1];
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, m_resolvedColorTexture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, m_resolvedDepthTexture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
|
||||
|
||||
// Bind resolved textures to resolved framebuffer.
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, m_resolvedColorTexture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, m_resolvedDepthTexture, 0);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
// Return to EFB framebuffer.
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
}
|
||||
|
||||
// Create XFB framebuffer; targets will be created elsewhere.
|
||||
|
||||
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
|
||||
|
||||
glGenFramebuffers(1, &m_xfbFramebuffer);
|
||||
|
||||
// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glScissor(0, 0, m_targetWidth, m_targetHeight);
|
||||
@ -180,7 +179,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
GLuint glObj[3];
|
||||
|
||||
@ -189,7 +188,7 @@ FramebufferManager::~FramebufferManager()
|
||||
glObj[0] = m_efbFramebuffer;
|
||||
glObj[1] = m_resolvedFramebuffer;
|
||||
glObj[2] = m_xfbFramebuffer;
|
||||
glDeleteFramebuffersEXT(3, glObj);
|
||||
glDeleteFramebuffers(3, glObj);
|
||||
m_efbFramebuffer = 0;
|
||||
m_xfbFramebuffer = 0;
|
||||
|
||||
@ -204,7 +203,7 @@ FramebufferManager::~FramebufferManager()
|
||||
if (m_msaaSamples <= 1)
|
||||
glDeleteTextures(2, glObj);
|
||||
else
|
||||
glDeleteRenderbuffersEXT(2, glObj);
|
||||
glDeleteRenderbuffers(2, glObj);
|
||||
m_efbColor = 0;
|
||||
m_efbDepth = 0;
|
||||
}
|
||||
@ -224,16 +223,16 @@ GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
||||
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
||||
glBlitFramebufferEXT(
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
glBlitFramebuffer(
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
return m_resolvedColorTexture;
|
||||
}
|
||||
@ -254,16 +253,16 @@ GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc)
|
||||
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
|
||||
glBlitFramebufferEXT(
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
glBlitFramebuffer(
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
return m_resolvedDepthTexture;
|
||||
}
|
||||
@ -284,7 +283,7 @@ void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c
|
||||
|
||||
void FramebufferManager::SetFramebuffer(GLuint fb)
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : GetEFBFramebuffer());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer());
|
||||
}
|
||||
|
||||
// Apply AA if enabled
|
||||
@ -298,106 +297,60 @@ GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_r
|
||||
return GetEFBDepthTexture(source_rect);
|
||||
}
|
||||
|
||||
XFBSource::~XFBSource()
|
||||
{
|
||||
glDeleteRenderbuffers(1, &renderbuf);
|
||||
}
|
||||
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
|
||||
{
|
||||
// Texture map xfbSource->texture onto the main buffer
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(sourcerc.left, sourcerc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0);
|
||||
glVertex2f(drawrc.left, drawrc.bottom);
|
||||
|
||||
glTexCoord2f(sourcerc.left, sourcerc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1);
|
||||
glVertex2f(drawrc.left, drawrc.top);
|
||||
|
||||
glTexCoord2f(sourcerc.right, sourcerc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1);
|
||||
glVertex2f(drawrc.right, drawrc.top);
|
||||
|
||||
glTexCoord2f(sourcerc.right, sourcerc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0);
|
||||
glVertex2f(drawrc.right, drawrc.bottom);
|
||||
glEnd();
|
||||
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuf);
|
||||
glBlitFramebuffer(sourcerc.left, sourcerc.bottom, sourcerc.right, sourcerc.top,
|
||||
drawrc.left, drawrc.bottom, drawrc.right, drawrc.top,
|
||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture);
|
||||
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, renderbuf);
|
||||
}
|
||||
|
||||
void XFBSource::CopyEFB(float Gamma)
|
||||
{
|
||||
// Copy EFB data to XFB and restore render target again
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer());
|
||||
|
||||
#if 0
|
||||
if (m_msaaSamples <= 1)
|
||||
#else
|
||||
if (!s_bHaveFramebufferBlit)
|
||||
#endif
|
||||
{
|
||||
// Just copy the EFB directly.
|
||||
// Bind texture.
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuf);
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::GetEFBFramebuffer());
|
||||
glBlitFramebuffer(
|
||||
0, 0, texWidth, texHeight,
|
||||
0, 0, texWidth, texHeight,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, texWidth, texHeight, 0);
|
||||
// Return to EFB.
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// OpenGL cannot copy directly from a multisampled framebuffer, so use
|
||||
// EXT_framebuffer_blit.
|
||||
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetEFBFramebuffer());
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, FramebufferManager::GetXFBFramebuffer());
|
||||
|
||||
// Bind texture.
|
||||
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, texture, 0);
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
glBlitFramebufferEXT(
|
||||
0, 0, texWidth, texHeight,
|
||||
0, 0, texWidth, texHeight,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Unbind texture.
|
||||
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::GetEFBFramebuffer());
|
||||
}
|
||||
}
|
||||
|
||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
||||
{
|
||||
GLuint texture;
|
||||
GLuint renderbuf;
|
||||
|
||||
glGenTextures(1, &texture);
|
||||
glGenRenderbuffers(1, &renderbuf);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, target_width, target_height);
|
||||
|
||||
#if 0// XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible.
|
||||
if (m_msaaSamples > 1)
|
||||
#else
|
||||
if (s_bHaveFramebufferBlit)
|
||||
#endif
|
||||
{
|
||||
// In MSAA mode, allocate the texture image here. In non-MSAA mode,
|
||||
// the image will be allocated by glCopyTexImage2D (later).
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, target_width, target_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
}
|
||||
|
||||
return new XFBSource(texture);
|
||||
return new XFBSource(renderbuf);
|
||||
}
|
||||
|
||||
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)
|
||||
|
@ -57,15 +57,15 @@ namespace OGL {
|
||||
|
||||
struct XFBSource : public XFBSourceBase
|
||||
{
|
||||
XFBSource(GLuint tex) : texture(tex) {}
|
||||
~XFBSource() { glDeleteTextures(1, &texture); }
|
||||
XFBSource(GLuint rbuf) : renderbuf(rbuf) {}
|
||||
~XFBSource();
|
||||
|
||||
void CopyEFB(float Gamma);
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
void Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
|
||||
|
||||
const GLuint texture;
|
||||
const GLuint renderbuf;
|
||||
};
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
|
@ -51,10 +51,10 @@ void VideoBackend::UpdateFPSDisplay(const char *text)
|
||||
}
|
||||
void InitInterface()
|
||||
{
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
#ifdef ANDROID
|
||||
GLInterface = new cInterfaceBase;
|
||||
#elif defined(USE_EGL) && USE_EGL
|
||||
GLInterface = new cInterfaceEGL;
|
||||
#elif defined(USE_WX) && USE_WX
|
||||
GLInterface = new cInterfaceWX;
|
||||
#elif defined(__APPLE__)
|
||||
GLInterface = new cInterfaceAGL;
|
||||
#elif defined(_WIN32)
|
||||
@ -70,14 +70,14 @@ GLuint OpenGL_CompileProgram ( const char* vertexShader, const char* fragmentSha
|
||||
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
GLuint programID = glCreateProgram();
|
||||
GLint Result = GL_FALSE;
|
||||
char stringBuffer[1024];
|
||||
GLsizei stringBufferUsage = 0;
|
||||
|
||||
// compile vertex shader
|
||||
glShaderSource(vertexShaderID, 1, &vertexShader, NULL);
|
||||
glCompileShader(vertexShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
GLint Result = GL_FALSE;
|
||||
char stringBuffer[1024];
|
||||
GLsizei stringBufferUsage = 0;
|
||||
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
@ -157,32 +157,26 @@ void OpenGL_ReportARBProgramError()
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
||||
{
|
||||
#ifndef USE_GLES
|
||||
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
unsigned int fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
const char *error = "-";
|
||||
const char *error = "unknown error";
|
||||
switch (fbo_status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
error = "INCOMPLETE_ATTACHMENT_EXT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
error = "INCOMPLETE_ATTACHMENT";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
||||
error = "INCOMPLETE_MISSING_ATTACHMENT_EXT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
error = "INCOMPLETE_MISSING_ATTACHMENT";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
||||
error = "INCOMPLETE_DIMENSIONS_EXT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
error = "INCOMPLETE_DRAW_BUFFER";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
||||
error = "INCOMPLETE_FORMATS_EXT";
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
error = "INCOMPLETE_READ_BUFFER";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
||||
error = "INCOMPLETE_DRAW_BUFFER_EXT";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
error = "INCOMPLETE_READ_BUFFER_EXT";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
error = "UNSUPPORTED_EXT";
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
error = "UNSUPPORTED";
|
||||
break;
|
||||
}
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n",
|
||||
|
@ -63,26 +63,22 @@ bool OpenGL_ReportFBOError(const char *function, const char *file, int line);
|
||||
#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError()
|
||||
#else
|
||||
#define GL_REPORT_ERROR() GL_NO_ERROR
|
||||
__forceinline GLenum GL_REPORT_ERROR() { return GL_NO_ERROR; }
|
||||
#define GL_REPORT_ERRORD() (void)GL_NO_ERROR
|
||||
#define GL_REPORT_FBO_ERROR() (void)true
|
||||
#define GL_REPORT_PROGRAM_ERROR() (void)0
|
||||
#endif
|
||||
|
||||
#if defined __APPLE__ || defined __linux__ || defined _WIN32
|
||||
#include <Cg/cg.h>
|
||||
#include <Cg/cgGL.h>
|
||||
#define HAVE_CG 1
|
||||
extern CGcontext g_cgcontext;
|
||||
extern CGprofile g_cgvProf, g_cgfProf;
|
||||
// this should be removed in future, but as long as glsl is unstable, we should really read this messages
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define DEBUG_GLSL 1
|
||||
#else
|
||||
#define DEBUG_GLSL 0
|
||||
#endif
|
||||
|
||||
// XXX: Dual-source blending in OpenGL does not work correctly yet. To make it
|
||||
// work, we may need to use glBindFragDataLocation. To use that, we need to
|
||||
// use GLSL shaders across the whole pipeline. Yikes!
|
||||
//#define USE_DUAL_SOURCE_BLEND
|
||||
|
||||
// TODO: should be removed if we use glsl a lot
|
||||
#define DEBUG_GLSL
|
||||
// Isn't defined if we aren't using GLEW 1.6
|
||||
#ifndef GL_ONE_MINUS_SRC1_ALPHA
|
||||
#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
|
||||
#endif
|
||||
|
||||
#endif // _GLINIT_H_
|
||||
|
@ -17,56 +17,18 @@
|
||||
|
||||
#include "GLUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "CPMemory.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "VertexManager.h"
|
||||
|
||||
#define COMPILED_CODE_SIZE 4096
|
||||
|
||||
// TODO: this guy is never initialized
|
||||
u32 s_prevcomponents; // previous state set
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_IX86
|
||||
#define USE_JIT
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
// Note the use of CallCdeclFunction3I etc.
|
||||
// This is a horrible hack that is necessary because in 64-bit mode, Opengl32.dll is based way, way above the 32-bit
|
||||
// address space that is within reach of a CALL, and just doing &fn gives us these high uncallable addresses. So we
|
||||
// want to grab the function pointers from the import table instead.
|
||||
|
||||
// This problem does not apply to glew functions, only core opengl32 functions.
|
||||
|
||||
// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state
|
||||
// machine.
|
||||
|
||||
#ifdef USE_JIT
|
||||
DECLARE_IMPORT(glNormalPointer);
|
||||
DECLARE_IMPORT(glVertexPointer);
|
||||
DECLARE_IMPORT(glColorPointer);
|
||||
DECLARE_IMPORT(glTexCoordPointer);
|
||||
#endif
|
||||
|
||||
class GLVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
u8 *m_compiledCode;
|
||||
PortableVertexDeclaration vtx_decl;
|
||||
|
||||
public:
|
||||
GLVertexFormat();
|
||||
~GLVertexFormat();
|
||||
|
||||
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
||||
virtual void SetupVertexPointers();
|
||||
virtual void EnableComponents(u32 components);
|
||||
};
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
@ -75,23 +37,14 @@ NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
|
||||
return new GLVertexFormat();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GLVertexFormat::GLVertexFormat()
|
||||
{
|
||||
#ifdef USE_JIT
|
||||
m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false);
|
||||
if (m_compiledCode)
|
||||
memset(m_compiledCode, 0, COMPILED_CODE_SIZE);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
GLVertexFormat::~GLVertexFormat()
|
||||
{
|
||||
#ifdef USE_JIT
|
||||
FreeMemoryPages(m_compiledCode, COMPILED_CODE_SIZE);
|
||||
m_compiledCode = 0;
|
||||
#endif
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
}
|
||||
|
||||
inline GLuint VarToGL(VarType t)
|
||||
@ -104,183 +57,56 @@ inline GLuint VarToGL(VarType t)
|
||||
|
||||
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
||||
{
|
||||
s_prevcomponents = 0;
|
||||
|
||||
vertex_stride = _vtx_decl.stride;
|
||||
using namespace Gen;
|
||||
this->vtx_decl = _vtx_decl;
|
||||
vertex_stride = vtx_decl.stride;
|
||||
|
||||
// We will not allow vertex components causing uneven strides.
|
||||
if (_vtx_decl.stride & 3)
|
||||
PanicAlert("Uneven vertex stride: %i", _vtx_decl.stride);
|
||||
|
||||
#ifdef USE_JIT
|
||||
Gen::XEmitter emit(m_compiledCode);
|
||||
// Alright, we have our vertex declaration. Compile some crazy code to set it quickly using GL.
|
||||
emit.ABI_EmitPrologue(6);
|
||||
if (vertex_stride & 3)
|
||||
PanicAlert("Uneven vertex stride: %i", vertex_stride);
|
||||
|
||||
emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0);
|
||||
VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
|
||||
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
// the element buffer is bound directly to the vao, so we must it set for every vao
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->m_index_buffers);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers);
|
||||
|
||||
if (_vtx_decl.num_normals >= 1)
|
||||
{
|
||||
emit.CallCdeclFunction3_I(glNormalPointer, VarToGL(_vtx_decl.normal_gl_type), _vtx_decl.stride, _vtx_decl.normal_offset[0]);
|
||||
if (_vtx_decl.num_normals == 3) {
|
||||
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM1_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[1]);
|
||||
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM2_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[2]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (_vtx_decl.color_offset[i] != -1)
|
||||
{
|
||||
if (i == 0)
|
||||
emit.CallCdeclFunction4_I(glColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]);
|
||||
else
|
||||
emit.CallCdeclFunction4((void *)glSecondaryColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (_vtx_decl.texcoord_offset[i] != -1)
|
||||
{
|
||||
int id = GL_TEXTURE0 + i;
|
||||
#ifdef _M_X64
|
||||
#ifdef _MSC_VER
|
||||
emit.MOV(32, R(RCX), Imm32(id));
|
||||
#else
|
||||
emit.MOV(32, R(RDI), Imm32(id));
|
||||
#endif
|
||||
#else
|
||||
emit.ABI_AlignStack(1 * 4);
|
||||
emit.PUSH(32, Imm32(id));
|
||||
#endif
|
||||
emit.CALL((void *)glClientActiveTexture);
|
||||
#ifndef _M_X64
|
||||
#ifdef _WIN32
|
||||
// don't inc stack on windows, stdcall
|
||||
#else
|
||||
emit.ABI_RestoreStack(1 * 4);
|
||||
#endif
|
||||
#endif
|
||||
emit.CallCdeclFunction4_I(
|
||||
glTexCoordPointer, _vtx_decl.texcoord_size[i], VarToGL(_vtx_decl.texcoord_gl_type[i]),
|
||||
_vtx_decl.stride, _vtx_decl.texcoord_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (_vtx_decl.posmtx_offset != -1)
|
||||
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, _vtx_decl.stride, _vtx_decl.posmtx_offset);
|
||||
|
||||
emit.ABI_EmitEpilogue(6);
|
||||
|
||||
if (emit.GetCodePtr() - (u8*)m_compiledCode > COMPILED_CODE_SIZE)
|
||||
Crash();
|
||||
|
||||
#endif
|
||||
this->vtx_decl = _vtx_decl;
|
||||
}
|
||||
|
||||
void GLVertexFormat::SetupVertexPointers() {
|
||||
// Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to
|
||||
// get around type checking errors, and call it.
|
||||
#ifdef USE_JIT
|
||||
((void (*)())(void*)m_compiledCode)();
|
||||
#else
|
||||
glVertexPointer(3, GL_FLOAT, vtx_decl.stride, VertexManager::s_pBaseBufferPointer);
|
||||
if (vtx_decl.num_normals >= 1) {
|
||||
glNormalPointer(VarToGL(vtx_decl.normal_gl_type), vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[0]));
|
||||
if (vtx_decl.num_normals == 3) {
|
||||
glVertexAttribPointer(SHADER_NORM1_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[1]));
|
||||
glVertexAttribPointer(SHADER_NORM2_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[2]));
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, vtx_decl.stride, (u8*)NULL);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (vtx_decl.num_normals > i) {
|
||||
glEnableVertexAttribArray(SHADER_NORM0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_NORM0_ATTRIB+i, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.normal_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (vtx_decl.color_offset[i] != -1) {
|
||||
if (i == 0)
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i]));
|
||||
else {
|
||||
glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i]));
|
||||
}
|
||||
glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_COLOR0_ATTRIB+i, 4, GL_UNSIGNED_BYTE, GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.color_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (vtx_decl.texcoord_offset[i] != -1) {
|
||||
int id = GL_TEXTURE0 + i;
|
||||
glClientActiveTexture(id);
|
||||
glTexCoordPointer(vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]),
|
||||
vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.texcoord_offset[i]));
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB+i, vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]),
|
||||
GL_FALSE, vtx_decl.stride, (u8*)NULL + vtx_decl.texcoord_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vtx_decl.posmtx_offset != -1) {
|
||||
glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset));
|
||||
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
glVertexAttribIPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, vtx_decl.stride, (u8*)NULL + vtx_decl.posmtx_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
vm->m_last_vao = VAO;
|
||||
}
|
||||
|
||||
void GLVertexFormat::SetupVertexPointers() {
|
||||
}
|
||||
|
||||
void GLVertexFormat::EnableComponents(u32 components)
|
||||
{
|
||||
if (s_prevcomponents != components)
|
||||
{
|
||||
VertexManager::Flush();
|
||||
|
||||
// matrices
|
||||
if ((components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX))
|
||||
{
|
||||
if (components & VB_HAS_POSMTXIDX)
|
||||
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
else
|
||||
glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
}
|
||||
|
||||
// normals
|
||||
if ((components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0))
|
||||
{
|
||||
if (components & VB_HAS_NRM0)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
}
|
||||
if ((components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1))
|
||||
{
|
||||
if (components & VB_HAS_NRM1) {
|
||||
glEnableVertexAttribArray(SHADER_NORM1_ATTRIB);
|
||||
glEnableVertexAttribArray(SHADER_NORM2_ATTRIB);
|
||||
}
|
||||
else {
|
||||
glDisableVertexAttribArray(SHADER_NORM1_ATTRIB);
|
||||
glDisableVertexAttribArray(SHADER_NORM2_ATTRIB);
|
||||
}
|
||||
}
|
||||
|
||||
// color
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if ((components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i)))
|
||||
{
|
||||
if (components & (VB_HAS_COL0 << i))
|
||||
glEnableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
||||
else
|
||||
glDisableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
// tex
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
||||
{
|
||||
glClientActiveTexture(GL_TEXTURE0 + i);
|
||||
if (components & (VB_HAS_UV0 << i))
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
else
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
s_prevcomponents = components;
|
||||
}
|
||||
}
|
||||
|
133
Source/Plugins/Plugin_VideoOGL/Src/PerfQuery.cpp
Normal file
133
Source/Plugins/Plugin_VideoOGL/Src/PerfQuery.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "RenderBase.h"
|
||||
#include "GLUtil.h"
|
||||
#include "PerfQuery.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
PerfQuery::PerfQuery()
|
||||
: m_query_read_pos()
|
||||
, m_query_count()
|
||||
{
|
||||
for (u32 i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
|
||||
glGenQueries(1, &m_query_buffer[i].query_id);
|
||||
|
||||
ResetQuery();
|
||||
}
|
||||
|
||||
PerfQuery::~PerfQuery()
|
||||
{
|
||||
for (u32 i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
|
||||
glDeleteQueries(1, &m_query_buffer[i].query_id);
|
||||
}
|
||||
|
||||
void PerfQuery::EnableQuery(PerfQueryGroup type)
|
||||
{
|
||||
// Is this sane?
|
||||
if (m_query_count > ARRAYSIZE(m_query_buffer) / 2)
|
||||
WeakFlush();
|
||||
|
||||
if (ARRAYSIZE(m_query_buffer) == m_query_count)
|
||||
{
|
||||
FlushOne();
|
||||
//ERROR_LOG(VIDEO, "flushed query buffer early!");
|
||||
}
|
||||
|
||||
// start query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ARRAYSIZE(m_query_buffer)];
|
||||
|
||||
glBeginQuery(GL_SAMPLES_PASSED, entry.query_id);
|
||||
entry.query_type = type;
|
||||
|
||||
++m_query_count;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::DisableQuery(PerfQueryGroup type)
|
||||
{
|
||||
// stop query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
glEndQuery(GL_SAMPLES_PASSED);
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfQuery::IsFlushed() const
|
||||
{
|
||||
return 0 == m_query_count;
|
||||
}
|
||||
|
||||
void PerfQuery::FlushOne()
|
||||
{
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
GLuint result = 0;
|
||||
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result);
|
||||
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % ARRAYSIZE(m_query_buffer);
|
||||
--m_query_count;
|
||||
}
|
||||
|
||||
// TODO: could selectively flush things, but I don't think that will do much
|
||||
void PerfQuery::FlushResults()
|
||||
{
|
||||
while (!IsFlushed())
|
||||
FlushOne();
|
||||
}
|
||||
|
||||
void PerfQuery::WeakFlush()
|
||||
{
|
||||
while (!IsFlushed())
|
||||
{
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
GLuint result = GL_FALSE;
|
||||
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);
|
||||
|
||||
if (GL_TRUE == result)
|
||||
{
|
||||
FlushOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::ResetQuery()
|
||||
{
|
||||
m_query_count = 0;
|
||||
std::fill_n(m_results, ARRAYSIZE(m_results), 0);
|
||||
}
|
||||
|
||||
u32 PerfQuery::GetQueryResult(PerfQueryType type)
|
||||
{
|
||||
u32 result = 0;
|
||||
|
||||
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP];
|
||||
}
|
||||
else if (type == PQ_BLEND_INPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_EFB_COPY_CLOCKS)
|
||||
{
|
||||
result = m_results[PQG_EFB_COPY_CLOCKS];
|
||||
}
|
||||
|
||||
return result / 4;
|
||||
}
|
||||
|
||||
} // namespace
|
46
Source/Plugins/Plugin_VideoOGL/Src/PerfQuery.h
Normal file
46
Source/Plugins/Plugin_VideoOGL/Src/PerfQuery.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef _PERFQUERY_H_
|
||||
#define _PERFQUERY_H_
|
||||
|
||||
#include "PerfQueryBase.h"
|
||||
|
||||
namespace OGL {
|
||||
|
||||
class PerfQuery : public PerfQueryBase
|
||||
{
|
||||
public:
|
||||
PerfQuery();
|
||||
~PerfQuery();
|
||||
|
||||
void EnableQuery(PerfQueryGroup type);
|
||||
void DisableQuery(PerfQueryGroup type);
|
||||
void ResetQuery();
|
||||
u32 GetQueryResult(PerfQueryType type);
|
||||
void FlushResults();
|
||||
bool IsFlushed() const;
|
||||
|
||||
private:
|
||||
struct ActiveQuery
|
||||
{
|
||||
GLuint query_id;
|
||||
PerfQueryGroup query_type;
|
||||
};
|
||||
|
||||
// when testing in SMS: 64 was too small, 128 was ok
|
||||
static const u32 PERF_QUERY_BUFFER_SIZE = 512;
|
||||
|
||||
void WeakFlush();
|
||||
// Only use when non-empty
|
||||
void FlushOne();
|
||||
|
||||
// This contains gl query objects with unretrieved results.
|
||||
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
|
||||
u32 m_query_read_pos;
|
||||
|
||||
// TODO: sloppy
|
||||
volatile u32 m_query_count;
|
||||
volatile u32 m_results[PQG_NUM_MEMBERS];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _PERFQUERY_H_
|
@ -27,344 +27,88 @@
|
||||
#include "Common.h"
|
||||
#include "Render.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "StringUtil.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static int s_nMaxPixelInstructions;
|
||||
static GLuint s_ColorMatrixProgram = 0;
|
||||
static GLuint s_DepthMatrixProgram = 0;
|
||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
||||
PixelShaderUid PixelShaderCache::s_curuid;
|
||||
bool PixelShaderCache::s_displayCompileAlert;
|
||||
GLuint PixelShaderCache::CurrentShader;
|
||||
bool PixelShaderCache::ShaderEnabled;
|
||||
|
||||
PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry = NULL;
|
||||
PixelShaderUid PixelShaderCache::last_uid;
|
||||
|
||||
GLuint PixelShaderCache::GetDepthMatrixProgram()
|
||||
void SetPSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
|
||||
{
|
||||
return s_DepthMatrixProgram;
|
||||
}
|
||||
|
||||
GLuint PixelShaderCache::GetColorMatrixProgram()
|
||||
{
|
||||
return s_ColorMatrixProgram;
|
||||
}
|
||||
|
||||
void PixelShaderCache::Init()
|
||||
{
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
CurrentShader = 0;
|
||||
last_entry = NULL;
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
s_displayCompileAlert = true;
|
||||
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
|
||||
|
||||
if(s_nMaxPixelInstructions == 0) // Some combination of drivers and hardware returns zero for some reason.
|
||||
s_nMaxPixelInstructions = 4096;
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxPixelInstructions = 4096;
|
||||
#if CG_VERSION_NUM == 2100
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
|
||||
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
s_nMaxPixelInstructions = 4096;
|
||||
}
|
||||
#endif
|
||||
|
||||
int maxinst, maxattribs;
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst);
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs);
|
||||
INFO_LOG(VIDEO, "pixel max_alu=%d, max_inst=%d, max_attrib=%d", s_nMaxPixelInstructions, maxinst, maxattribs);
|
||||
|
||||
char pmatrixprog[2048];
|
||||
sprintf(pmatrixprog, "!!ARBfp1.0"
|
||||
"TEMP R0;\n"
|
||||
"TEMP R1;\n"
|
||||
"PARAM K0 = { 0.5, 0.5, 0.5, 0.5};\n"
|
||||
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
|
||||
"MUL R0, R0, program.env[%d];\n"
|
||||
"ADD R0, R0, K0;\n"
|
||||
"FLR R0, R0;\n"
|
||||
"MUL R0, R0, program.env[%d];\n"
|
||||
"DP4 R1.x, R0, program.env[%d];\n"
|
||||
"DP4 R1.y, R0, program.env[%d];\n"
|
||||
"DP4 R1.z, R0, program.env[%d];\n"
|
||||
"DP4 R1.w, R0, program.env[%d];\n"
|
||||
"ADD result.color, R1, program.env[%d];\n"
|
||||
"END\n",C_COLORMATRIX+5,C_COLORMATRIX+6, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+2, C_COLORMATRIX+3, C_COLORMATRIX+4);
|
||||
glGenProgramsARB(1, &s_ColorMatrixProgram);
|
||||
SetCurrentShader(s_ColorMatrixProgram);
|
||||
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog);
|
||||
|
||||
GLenum err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "Failed to create color matrix fragment program");
|
||||
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
|
||||
s_ColorMatrixProgram = 0;
|
||||
}
|
||||
|
||||
sprintf(pmatrixprog, "!!ARBfp1.0\n"
|
||||
"TEMP R0;\n"
|
||||
"TEMP R1;\n"
|
||||
"TEMP R2;\n"
|
||||
//16777215/16777216*256, 1/255, 256, 0
|
||||
"PARAM K0 = { 255.99998474121, 0.003921568627451, 256.0, 0.0};\n"
|
||||
"PARAM K1 = { 15.0, 0.066666666666, 0.0, 0.0};\n"
|
||||
//sample the depth value
|
||||
"TEX R2, fragment.texcoord[0], texture[0], RECT;\n"
|
||||
|
||||
//scale from [0*16777216..1*16777216] to
|
||||
//[0*16777215..1*16777215], multiply by 256
|
||||
"MUL R0, R2.x, K0.x;\n" // *16777215/16777216*256
|
||||
|
||||
//It is easy to get bad results due to low precision
|
||||
//here, for example converting like this:
|
||||
//MUL R0,R0,{ 65536, 256, 1, 16777216 }
|
||||
//FRC R0,R0
|
||||
//gives {?, 128/255, 254/255, ?} for depth value 254/255
|
||||
//on some gpus
|
||||
|
||||
"FLR R0.x,R0;\n" //bits 31..24
|
||||
|
||||
"SUB R0.yzw,R0,R0.x;\n" //subtract bits 31..24 from rest
|
||||
"MUL R0.yzw,R0,K0.z;\n" // *256
|
||||
"FLR R0.y,R0;\n" //bits 23..16
|
||||
|
||||
"SUB R0.zw,R0,R0.y;\n" //subtract bits 23..16 from rest
|
||||
"MUL R0.zw,R0,K0.z;\n" // *256
|
||||
"FLR R0.z,R0;\n" //bits 15..8
|
||||
|
||||
"MOV R0.w,R0.x;\n" //duplicate bit 31..24
|
||||
|
||||
"MUL R0,R0,K0.y;\n" // /255
|
||||
|
||||
"MUL R0.w,R0,K1.x;\n" // *15
|
||||
"FLR R0.w,R0;\n" //bits 31..28
|
||||
"MUL R0.w,R0,K1.y;\n" // /15
|
||||
|
||||
"DP4 R1.x, R0, program.env[%d];\n"
|
||||
"DP4 R1.y, R0, program.env[%d];\n"
|
||||
"DP4 R1.z, R0, program.env[%d];\n"
|
||||
"DP4 R1.w, R0, program.env[%d];\n"
|
||||
"ADD result.color, R1, program.env[%d];\n"
|
||||
"END\n", C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+2, C_COLORMATRIX+3, C_COLORMATRIX+4);
|
||||
glGenProgramsARB(1, &s_DepthMatrixProgram);
|
||||
SetCurrentShader(s_DepthMatrixProgram);
|
||||
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog);
|
||||
|
||||
err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "Failed to create depth matrix fragment program");
|
||||
glDeleteProgramsARB(1, &s_DepthMatrixProgram);
|
||||
s_DepthMatrixProgram = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PixelShaderCache::Shutdown()
|
||||
{
|
||||
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
|
||||
s_ColorMatrixProgram = 0;
|
||||
glDeleteProgramsARB(1, &s_DepthMatrixProgram);
|
||||
s_DepthMatrixProgram = 0;
|
||||
PSCache::iterator iter = PixelShaders.begin();
|
||||
for (; iter != PixelShaders.end(); iter++)
|
||||
iter->second.Destroy();
|
||||
PixelShaders.clear();
|
||||
}
|
||||
|
||||
FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
{
|
||||
PixelShaderUid uid;
|
||||
GetPixelShaderUid(uid, dstAlphaMode, API_OPENGL, components);
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
if (!strcmp(name, UniformNames[a]))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
if (tmp.shader.UniformLocations[a] == -1)
|
||||
return;
|
||||
else
|
||||
{
|
||||
glUniform4fv(tmp.shader.UniformLocations[a] + offset, count, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
PSCache::iterator iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end())
|
||||
{
|
||||
PSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
PSCacheEntry& newentry = PixelShaders[uid];
|
||||
last_entry = &newentry;
|
||||
PixelShaderCode code;
|
||||
GeneratePixelShaderCode(code, dstAlphaMode, API_OPENGL, components);
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
newentry.shader.strprog = code.GetBuffer();
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
|
||||
SaveData(szTemp, code.GetBuffer()); /// XXX
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!code.GetBuffer() || !CompilePixelShader(newentry.shader, code.GetBuffer())) {
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram)
|
||||
{
|
||||
GLenum err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "glError %08x before PS!", err);
|
||||
}
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
char stropt[128];
|
||||
sprintf(stropt, "MaxLocalParams=224,NumInstructionSlots=%d", s_nMaxPixelInstructions);
|
||||
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
|
||||
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts);
|
||||
|
||||
// handle errors
|
||||
if (!cgIsProgram(tempprog))
|
||||
{
|
||||
cgDestroyProgram(tempprog);
|
||||
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file(szTemp);
|
||||
file << pstrprogram;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile pixel 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 (%d):\n%s",
|
||||
szTemp,
|
||||
g_cgfProf,
|
||||
cgGetLastListing(g_cgcontext));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle warnings
|
||||
if (cgGetError() != CG_NO_ERROR)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext));
|
||||
WARN_LOG(VIDEO, "%s", pstrprogram);
|
||||
}
|
||||
|
||||
// This looks evil - we modify the program through the const char * we got from cgGetProgramString!
|
||||
// It SHOULD not have any nasty side effects though - but you never know...
|
||||
char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
|
||||
char *plocal = strstr(pcompiledprog, "program.local");
|
||||
while (plocal != NULL)
|
||||
{
|
||||
const char *penv = " program.env";
|
||||
memcpy(plocal, penv, 13);
|
||||
plocal = strstr(plocal+13, "program.local");
|
||||
}
|
||||
|
||||
glGenProgramsARB(1, &ps.glprogid);
|
||||
SetCurrentShader(ps.glprogid);
|
||||
glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
|
||||
|
||||
err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
GLint error_pos, native_limit;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native_limit);
|
||||
// Error occur
|
||||
if (error_pos != -1) {
|
||||
const char *program_error = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
char line[256];
|
||||
strncpy(line, (const char *)pcompiledprog + error_pos, 255);
|
||||
line[255] = 0;
|
||||
ERROR_LOG(VIDEO, "Error at %i: %s", error_pos, program_error);
|
||||
ERROR_LOG(VIDEO, "Line dump: \n%s", line);
|
||||
} else if (native_limit != -1) {
|
||||
ERROR_LOG(VIDEO, "Hit limit? %i", native_limit);
|
||||
// TODO
|
||||
}
|
||||
ERROR_LOG(VIDEO, "%s", pstrprogram);
|
||||
ERROR_LOG(VIDEO, "%s", pcompiledprog);
|
||||
}
|
||||
|
||||
cgDestroyProgram(tempprog);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Disable Fragment programs and reset the selected Program
|
||||
void PixelShaderCache::DisableShader()
|
||||
{
|
||||
if(ShaderEnabled)
|
||||
{
|
||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
ShaderEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
//bind a program if is diferent from the binded oone
|
||||
void PixelShaderCache::SetCurrentShader(GLuint Shader)
|
||||
{
|
||||
if(!ShaderEnabled)
|
||||
{
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
}
|
||||
if(CurrentShader != Shader)
|
||||
{
|
||||
if(Shader != 0)
|
||||
CurrentShader = Shader;
|
||||
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, CurrentShader);
|
||||
}
|
||||
}
|
||||
|
||||
// Renderer functions
|
||||
void Renderer::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
float f[4] = { f1, f2, f3, f4 };
|
||||
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
|
||||
float const f[4] = {f1, f2, f3, f4};
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetPSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++,f+=4)
|
||||
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number + i, f);
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
@ -1,90 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _PIXELSHADERCACHE_H_
|
||||
#define _PIXELSHADERCACHE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "BPMemory.h"
|
||||
#include "PixelShaderGen.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
struct FRAGMENTSHADER
|
||||
{
|
||||
FRAGMENTSHADER() : glprogid(0) { }
|
||||
void Destroy()
|
||||
{
|
||||
if (glprogid)
|
||||
{
|
||||
glDeleteProgramsARB(1, &glprogid);
|
||||
glprogid = 0;
|
||||
}
|
||||
}
|
||||
GLuint glprogid; // opengl program id
|
||||
std::string strprog;
|
||||
};
|
||||
|
||||
class PixelShaderCache
|
||||
{
|
||||
struct PSCacheEntry
|
||||
{
|
||||
FRAGMENTSHADER shader;
|
||||
PSCacheEntry() {}
|
||||
~PSCacheEntry() {}
|
||||
void Destroy()
|
||||
{
|
||||
shader.Destroy();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
||||
|
||||
static PSCache PixelShaders;
|
||||
|
||||
static PixelShaderUid s_curuid; // the current pixel shader uid (progressively changed as memory is written)
|
||||
|
||||
static bool s_displayCompileAlert;
|
||||
|
||||
static GLuint CurrentShader;
|
||||
static PSCacheEntry* last_entry;
|
||||
static PixelShaderUid last_uid;
|
||||
|
||||
static bool ShaderEnabled;
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static FRAGMENTSHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram);
|
||||
|
||||
static GLuint GetColorMatrixProgram();
|
||||
|
||||
static GLuint GetDepthMatrixProgram();
|
||||
|
||||
static void SetCurrentShader(GLuint Shader);
|
||||
|
||||
static void DisableShader();
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
||||
#endif // _PIXELSHADERCACHE_H_
|
@ -20,7 +20,8 @@
|
||||
#include "VideoConfig.h"
|
||||
#include "GLUtil.h"
|
||||
#include "PostProcessing.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "FramebufferManager.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
@ -29,16 +30,72 @@ namespace PostProcessing
|
||||
{
|
||||
|
||||
static std::string s_currentShader;
|
||||
static FRAGMENTSHADER s_shader;
|
||||
static SHADER s_shader;
|
||||
static bool s_enable;
|
||||
|
||||
static u32 s_width;
|
||||
static u32 s_height;
|
||||
static GLuint s_fbo;
|
||||
static GLuint s_texture;
|
||||
static GLuint s_vao;
|
||||
static GLuint s_vbo;
|
||||
|
||||
static GLuint s_uniform_resolution;
|
||||
|
||||
static char s_vertex_shader[] =
|
||||
"in vec2 rawpos;\n"
|
||||
"in vec2 tex0;\n"
|
||||
"out vec2 uv0;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
" uv0 = tex0;\n"
|
||||
"}\n";
|
||||
|
||||
void Init()
|
||||
{
|
||||
s_currentShader = "";
|
||||
s_enable = 0;
|
||||
s_width = 0;
|
||||
s_height = 0;
|
||||
|
||||
glGenFramebuffers(1, &s_fbo);
|
||||
glGenTextures(1, &s_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); // disable mipmaps
|
||||
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_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s_fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_texture, 0);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
glGenBuffers(1, &s_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_vbo);
|
||||
GLfloat vertices[] = {
|
||||
-1.f, -1.f, 0.f, 0.f,
|
||||
-1.f, 1.f, 0.f, 1.f,
|
||||
1.f, -1.f, 1.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glGenVertexArrays(1, &s_vao);
|
||||
glBindVertexArray( s_vao );
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
s_shader.Destroy();
|
||||
|
||||
glDeleteFramebuffers(1, &s_vbo);
|
||||
glDeleteTextures(1, &s_texture);
|
||||
|
||||
glDeleteBuffers(1, &s_vbo);
|
||||
glDeleteVertexArrays(1, &s_vao);
|
||||
}
|
||||
|
||||
void ReloadShader()
|
||||
@ -46,45 +103,83 @@ void ReloadShader()
|
||||
s_currentShader = "";
|
||||
}
|
||||
|
||||
bool ApplyShader()
|
||||
void BindTargetFramebuffer ()
|
||||
{
|
||||
if (s_currentShader != File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt")
|
||||
{
|
||||
// Set immediately to prevent endless recompiles on failure.
|
||||
if (!g_ActiveConfig.sPostProcessingShader.empty())
|
||||
s_currentShader = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt";
|
||||
else
|
||||
s_currentShader.clear();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_enable ? s_fbo : 0);
|
||||
}
|
||||
|
||||
s_shader.Destroy();
|
||||
void BlitToScreen()
|
||||
{
|
||||
if(!s_enable) return;
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glViewport(0, 0, s_width, s_height);
|
||||
|
||||
glBindVertexArray(s_vao);
|
||||
s_shader.Bind();
|
||||
|
||||
glUniform4f(s_uniform_resolution, (float)s_width, (float)s_height, 1.0f/(float)s_width, 1.0f/(float)s_height);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
/* glBindFramebuffer(GL_READ_FRAMEBUFFER, s_fbo);
|
||||
|
||||
glBlitFramebuffer(rc.left, rc.bottom, rc.right, rc.top,
|
||||
rc.left, rc.bottom, rc.right, rc.top,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);*/
|
||||
}
|
||||
|
||||
if (!s_currentShader.empty())
|
||||
{
|
||||
std::string code;
|
||||
if (File::ReadFileToString(true, s_currentShader.c_str(), code))
|
||||
{
|
||||
if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str()))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
void Update ( u32 width, u32 height )
|
||||
{
|
||||
ApplyShader();
|
||||
|
||||
if (s_shader.glprogid != 0)
|
||||
{
|
||||
PixelShaderCache::SetCurrentShader(s_shader.glprogid);
|
||||
return true;
|
||||
if(s_enable && (width != s_width || height != s_height)) {
|
||||
s_width = width;
|
||||
s_height = height;
|
||||
|
||||
// alloc texture for framebuffer
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PixelShaderCache::DisableShader();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplyShader()
|
||||
{
|
||||
// shader didn't changed
|
||||
if (s_currentShader == g_ActiveConfig.sPostProcessingShader) return;
|
||||
s_currentShader = g_ActiveConfig.sPostProcessingShader;
|
||||
s_enable = false;
|
||||
s_shader.Destroy();
|
||||
|
||||
// shader disabled
|
||||
if (g_ActiveConfig.sPostProcessingShader == "") return;
|
||||
|
||||
// so need to compile shader
|
||||
|
||||
// loading shader code
|
||||
std::string code;
|
||||
std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt";
|
||||
if(!File::ReadFileToString(true, path.c_str(), code)) {
|
||||
ERROR_LOG(VIDEO, "post-processing shader not found: %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// and compile it
|
||||
if (!ProgramShaderCache::CompileShader(s_shader, s_vertex_shader, code.c_str())) {
|
||||
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// read uniform locations
|
||||
s_uniform_resolution = glGetUniformLocation(s_shader.glprogid, "resolution");
|
||||
|
||||
// successful
|
||||
s_enable = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -30,9 +30,13 @@ namespace PostProcessing
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void BindTargetFramebuffer();
|
||||
void BlitToScreen();
|
||||
void Update(u32 width, u32 height);
|
||||
|
||||
void ReloadShader();
|
||||
// Returns false if no shader was applied.
|
||||
bool ApplyShader();
|
||||
|
||||
void ApplyShader();
|
||||
|
||||
} // namespace
|
||||
|
||||
|
540
Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp
Normal file
540
Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp
Normal file
@ -0,0 +1,540 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "MathUtil.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "Debugger.h"
|
||||
#include "Statistics.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "Render.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static const u32 UBO_LENGTH = 32*1024*1024;
|
||||
|
||||
GLintptr ProgramShaderCache::s_vs_data_size;
|
||||
GLintptr ProgramShaderCache::s_ps_data_size;
|
||||
GLintptr ProgramShaderCache::s_vs_data_offset;
|
||||
u8 *ProgramShaderCache::s_ubo_buffer;
|
||||
u32 ProgramShaderCache::s_ubo_buffer_size;
|
||||
bool ProgramShaderCache::s_ubo_dirty;
|
||||
|
||||
static StreamBuffer *s_buffer;
|
||||
|
||||
LinearDiskCache<SHADERUID, u8> g_program_disk_cache;
|
||||
static GLuint CurrentProgram = 0;
|
||||
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
|
||||
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
|
||||
SHADERUID ProgramShaderCache::last_uid;
|
||||
|
||||
static char s_glsl_header[1024] = "";
|
||||
|
||||
const char *UniformNames[NUM_UNIFORMS] =
|
||||
{
|
||||
// PIXEL SHADER UNIFORMS
|
||||
I_COLORS,
|
||||
I_KCOLORS,
|
||||
I_ALPHA,
|
||||
I_TEXDIMS,
|
||||
I_ZBIAS ,
|
||||
I_INDTEXSCALE ,
|
||||
I_INDTEXMTX,
|
||||
I_FOG,
|
||||
I_PLIGHTS,
|
||||
I_PMATERIALS,
|
||||
// VERTEX SHADER UNIFORMS
|
||||
I_POSNORMALMATRIX,
|
||||
I_PROJECTION ,
|
||||
I_MATERIALS,
|
||||
I_LIGHTS,
|
||||
I_TEXMATRICES,
|
||||
I_TRANSFORMMATRICES ,
|
||||
I_NORMALMATRICES ,
|
||||
I_POSTTRANSFORMMATRICES,
|
||||
I_DEPTHPARAMS,
|
||||
};
|
||||
|
||||
void SHADER::SetProgramVariables()
|
||||
{
|
||||
// glsl shader must be bind to set samplers
|
||||
Bind();
|
||||
|
||||
// Bind UBO
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock");
|
||||
GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock");
|
||||
|
||||
if(PSBlock_id != -1)
|
||||
glUniformBlockBinding(glprogid, PSBlock_id, 1);
|
||||
if(VSBlock_id != -1)
|
||||
glUniformBlockBinding(glprogid, VSBlock_id, 2);
|
||||
}
|
||||
|
||||
// We cache our uniform locations for now
|
||||
// Once we move up to a newer version of GLSL, ~1.30
|
||||
// We can remove this
|
||||
|
||||
// (Sonicadvance): For some reason this fails on my hardware
|
||||
//glGetUniformIndices(glprogid, NUM_UNIFORMS, UniformNames, UniformLocations);
|
||||
// Got to do it this crappy way.
|
||||
UniformLocations[0] = glGetUniformLocation(glprogid, UniformNames[0]);
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
for (int a = 1; a < NUM_UNIFORMS; ++a)
|
||||
UniformLocations[a] = glGetUniformLocation(glprogid, UniformNames[a]);
|
||||
|
||||
// Bind Texture Sampler
|
||||
for (int a = 0; a <= 9; ++a)
|
||||
{
|
||||
char name[8];
|
||||
snprintf(name, 8, "samp%d", a);
|
||||
|
||||
// Still need to get sampler locations since we aren't binding them statically in the shaders
|
||||
int loc = glGetUniformLocation(glprogid, name);
|
||||
if (loc != -1)
|
||||
glUniform1i(loc, a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SHADER::SetProgramBindings()
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
|
||||
{
|
||||
// So we do support extended blending
|
||||
// So we need to set a few more things here.
|
||||
// Bind our out locations
|
||||
glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0");
|
||||
glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1");
|
||||
}
|
||||
else
|
||||
glBindFragDataLocation(glprogid, 0, "ocol0");
|
||||
|
||||
// Need to set some attribute locations
|
||||
glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "fposmtx");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0");
|
||||
glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0");
|
||||
glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1");
|
||||
glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2");
|
||||
|
||||
for(int i=0; i<8; i++) {
|
||||
char attrib_name[8];
|
||||
snprintf(attrib_name, 8, "tex%d", i);
|
||||
glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB+i, attrib_name);
|
||||
}
|
||||
}
|
||||
|
||||
void SHADER::Bind()
|
||||
{
|
||||
if(CurrentProgram != glprogid)
|
||||
{
|
||||
glUseProgram(glprogid);
|
||||
CurrentProgram = glprogid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProgramShaderCache::SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count)
|
||||
{
|
||||
s_ubo_dirty = true;
|
||||
memcpy(s_ubo_buffer+(offset*4*sizeof(float)), f, count*4*sizeof(float));
|
||||
}
|
||||
|
||||
void ProgramShaderCache::SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count)
|
||||
{
|
||||
s_ubo_dirty = true;
|
||||
memcpy(s_ubo_buffer+(offset*4*sizeof(float))+s_vs_data_offset, f, count*4*sizeof(float));
|
||||
}
|
||||
|
||||
void ProgramShaderCache::UploadConstants()
|
||||
{
|
||||
if(s_ubo_dirty) {
|
||||
s_buffer->Alloc(s_ubo_buffer_size);
|
||||
size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_ps_data_size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_vs_data_size);
|
||||
s_ubo_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint ProgramShaderCache::GetCurrentProgram(void)
|
||||
{
|
||||
return CurrentProgram;
|
||||
}
|
||||
|
||||
SHADER* ProgramShaderCache::SetShader ( DSTALPHA_MODE dstAlphaMode, u32 components )
|
||||
{
|
||||
SHADERUID uid;
|
||||
GetShaderId(&uid, dstAlphaMode, components);
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
// Check if shader is already in cache
|
||||
PCache::iterator iter = pshaders.find(uid);
|
||||
if (iter != pshaders.end())
|
||||
{
|
||||
PCacheEntry *entry = &iter->second;
|
||||
last_entry = entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
PCacheEntry& newentry = pshaders[uid];
|
||||
last_entry = &newentry;
|
||||
newentry.in_cache = 0;
|
||||
|
||||
VertexShaderCode vcode;
|
||||
PixelShaderCode pcode;
|
||||
GenerateVertexShaderCode(vcode, components, API_OPENGL);
|
||||
GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components);
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
newentry.shader.strvprog = vcode.GetBuffer();
|
||||
newentry.shader.strpprog = pcode.GetBuffer();
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS) {
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
SaveData(szTemp, vcode.GetBuffer());
|
||||
sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
SaveData(szTemp, pcode.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer())) {
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool ProgramShaderCache::CompileShader ( SHADER& shader, const char* vcode, const char* pcode )
|
||||
{
|
||||
GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode);
|
||||
GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode);
|
||||
|
||||
if(!vsid || !psid)
|
||||
{
|
||||
glDeleteShader(vsid);
|
||||
glDeleteShader(psid);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint pid = shader.glprogid = glCreateProgram();;
|
||||
|
||||
glAttachShader(pid, vsid);
|
||||
glAttachShader(pid, psid);
|
||||
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
shader.SetProgramBindings();
|
||||
|
||||
glLinkProgram(pid);
|
||||
|
||||
// original shaders aren't needed any more
|
||||
glDeleteShader(vsid);
|
||||
glDeleteShader(psid);
|
||||
|
||||
GLint linkStatus;
|
||||
glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus);
|
||||
GLsizei length = 0;
|
||||
glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length);
|
||||
if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
|
||||
{
|
||||
GLsizei charsWritten;
|
||||
GLchar* infoLog = new GLchar[length];
|
||||
glGetProgramInfoLog(pid, length, &charsWritten, infoLog);
|
||||
ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog);
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sp_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), pid);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << infoLog << s_glsl_header << vcode << s_glsl_header << pcode;
|
||||
file.close();
|
||||
delete [] infoLog;
|
||||
}
|
||||
if (linkStatus != GL_TRUE)
|
||||
{
|
||||
// Compile failed
|
||||
ERROR_LOG(VIDEO, "Program linking failed; see info log");
|
||||
|
||||
// Don't try to use this shader
|
||||
glDeleteProgram(pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
shader.SetProgramVariables();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint ProgramShaderCache::CompileSingleShader (GLuint type, const char* code )
|
||||
{
|
||||
GLuint result = glCreateShader(type);
|
||||
|
||||
const char *src[] = {s_glsl_header, code};
|
||||
|
||||
glShaderSource(result, 2, src, NULL);
|
||||
glCompileShader(result);
|
||||
GLint compileStatus;
|
||||
glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus);
|
||||
GLsizei length = 0;
|
||||
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length);
|
||||
if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
|
||||
{
|
||||
GLsizei charsWritten;
|
||||
GLchar* infoLog = new GLchar[length];
|
||||
glGetShaderInfoLog(result, length, &charsWritten, infoLog);
|
||||
ERROR_LOG(VIDEO, "PS Shader info log:\n%s", infoLog);
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sps_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), result);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << infoLog << s_glsl_header << code;
|
||||
file.close();
|
||||
delete[] infoLog;
|
||||
}
|
||||
if (compileStatus != GL_TRUE)
|
||||
{
|
||||
// Compile failed
|
||||
ERROR_LOG(VIDEO, "Shader compilation failed; see info log");
|
||||
|
||||
// Don't try to use this shader
|
||||
glDeleteShader(result);
|
||||
return 0;
|
||||
}
|
||||
(void)GL_REPORT_ERROR();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ProgramShaderCache::GetShaderId ( SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components )
|
||||
{
|
||||
GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components);
|
||||
GetVertexShaderUid(uid->vuid, components, API_OPENGL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram(void)
|
||||
{
|
||||
return *last_entry;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::Init(void)
|
||||
{
|
||||
// We have to get the UBO alignment here because
|
||||
// if we generate a buffer that isn't aligned
|
||||
// then the UBO will fail.
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
GLint Align;
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &Align);
|
||||
|
||||
s_ps_data_size = C_PENVCONST_END * sizeof(float) * 4;
|
||||
s_vs_data_size = C_VENVCONST_END * sizeof(float) * 4;
|
||||
s_vs_data_offset = ROUND_UP(s_ps_data_size, Align);
|
||||
s_ubo_buffer_size = ROUND_UP(s_ps_data_size, Align) + ROUND_UP(s_vs_data_size, Align);
|
||||
|
||||
// We multiply by *4*4 because we need to get down to basic machine units.
|
||||
// So multiply by four to get how many floats we have from vec4s
|
||||
// Then once more to get bytes
|
||||
s_buffer = new StreamBuffer(GL_UNIFORM_BUFFER, UBO_LENGTH);
|
||||
|
||||
s_ubo_buffer = new u8[s_ubo_buffer_size];
|
||||
memset(s_ubo_buffer, 0, s_ubo_buffer_size);
|
||||
s_ubo_dirty = true;
|
||||
}
|
||||
|
||||
// Read our shader cache, only if supported
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
{
|
||||
GLint Supported;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
|
||||
if(!Supported)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So disable shader cache.");
|
||||
g_ogl_config.bSupportsGLSLCache = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
|
||||
ProgramShaderCacheInserter inserter;
|
||||
g_program_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
}
|
||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
||||
}
|
||||
|
||||
CreateHeader();
|
||||
|
||||
CurrentProgram = 0;
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::Shutdown(void)
|
||||
{
|
||||
// store all shaders in cache on disk
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
{
|
||||
PCache::iterator iter = pshaders.begin();
|
||||
for (; iter != pshaders.end(); ++iter)
|
||||
{
|
||||
if(iter->second.in_cache) continue;
|
||||
|
||||
GLint binary_size;
|
||||
glGetProgramiv(iter->second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
|
||||
if(!binary_size) continue;
|
||||
|
||||
u8 *data = new u8[binary_size+sizeof(GLenum)];
|
||||
u8 *binary = data + sizeof(GLenum);
|
||||
GLenum *prog_format = (GLenum*)data;
|
||||
glGetProgramBinary(iter->second.shader.glprogid, binary_size, NULL, prog_format, binary);
|
||||
|
||||
g_program_disk_cache.Append(iter->first, data, binary_size+sizeof(GLenum));
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
g_program_disk_cache.Sync();
|
||||
g_program_disk_cache.Close();
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
PCache::iterator iter = pshaders.begin();
|
||||
for (; iter != pshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
pshaders.clear();
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
delete s_buffer;
|
||||
s_buffer = 0;
|
||||
delete [] s_ubo_buffer;
|
||||
s_ubo_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramShaderCache::CreateHeader ( void )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Intel Windows driver has a issue:
|
||||
// their glsl doesn't know about the ubo extension, so we can't load it.
|
||||
// but as version 140, ubo is in core and don't have to be loaded in glsl.
|
||||
// as sandy do ogl3.1, glsl 140 is supported, so force it in this way.
|
||||
// TODO: remove this again when the issue is fixed:
|
||||
// see http://communities.intel.com/thread/36084
|
||||
bool glsl140_hack = strcmp(g_ogl_config.gl_vendor, "Intel") == 0;
|
||||
#elif __APPLE__
|
||||
// as apple doesn't support glsl130 at all, we also have to use glsl140
|
||||
bool glsl140_hack = true;
|
||||
#else
|
||||
bool glsl140_hack = false;
|
||||
#endif
|
||||
|
||||
snprintf(s_glsl_header, sizeof(s_glsl_header),
|
||||
"#version %s\n"
|
||||
"%s\n" // tex_rect
|
||||
"%s\n" // ubo
|
||||
|
||||
"\n"// A few required defines and ones that will make our lives a lot easier
|
||||
"#define ATTRIN in\n"
|
||||
"#define ATTROUT out\n"
|
||||
"#define VARYIN centroid in\n"
|
||||
"#define VARYOUT centroid out\n"
|
||||
|
||||
// Silly differences
|
||||
"#define float2 vec2\n"
|
||||
"#define float3 vec3\n"
|
||||
"#define float4 vec4\n"
|
||||
|
||||
// hlsl to glsl function translation
|
||||
"#define frac(x) fract(x)\n"
|
||||
"#define saturate(x) clamp(x, 0.0f, 1.0f)\n"
|
||||
"#define lerp(x, y, z) mix(x, y, z)\n"
|
||||
|
||||
|
||||
, glsl140_hack ? "140" : "130"
|
||||
, glsl140_hack ? "#define texture2DRect texture" : "#extension GL_ARB_texture_rectangle : enable"
|
||||
, g_ActiveConfig.backend_info.bSupportsGLSLUBO && !glsl140_hack ? "#extension GL_ARB_uniform_buffer_object : enable" : "// ubo disabled"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void ProgramShaderCache::ProgramShaderCacheInserter::Read ( const SHADERUID& key, const u8* value, u32 value_size )
|
||||
{
|
||||
const u8 *binary = value+sizeof(GLenum);
|
||||
GLenum *prog_format = (GLenum*)value;
|
||||
GLint binary_size = value_size-sizeof(GLenum);
|
||||
|
||||
PCacheEntry entry;
|
||||
entry.in_cache = 1;
|
||||
entry.shader.glprogid = glCreateProgram();
|
||||
glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size);
|
||||
|
||||
GLint success;
|
||||
glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success);
|
||||
|
||||
if (success)
|
||||
{
|
||||
pshaders[key] = entry;
|
||||
entry.shader.SetProgramVariables();
|
||||
}
|
||||
else
|
||||
glDeleteProgram(entry.shader.glprogid);
|
||||
}
|
||||
|
||||
|
||||
} // namespace OGL
|
131
Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.h
Normal file
131
Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.h
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef PROGRAM_SHADER_CACHE_H_
|
||||
#define PROGRAM_SHADER_CACHE_H_
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include "PixelShaderGen.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "LinearDiskCache.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class SHADERUID
|
||||
{
|
||||
public:
|
||||
VertexShaderUid vuid;
|
||||
PixelShaderUid puid;
|
||||
|
||||
SHADERUID() {}
|
||||
|
||||
SHADERUID(const SHADERUID& r) : vuid(r.vuid), puid(r.puid) {}
|
||||
|
||||
bool operator <(const SHADERUID& r) const
|
||||
{
|
||||
if(puid < r.puid) return true;
|
||||
if(r.puid < puid) return false;
|
||||
if(vuid < r.vuid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator ==(const SHADERUID& r) const
|
||||
{
|
||||
return puid == r.puid && vuid == r.vuid;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const int NUM_UNIFORMS = 19;
|
||||
extern const char *UniformNames[NUM_UNIFORMS];
|
||||
|
||||
struct SHADER
|
||||
{
|
||||
SHADER() : glprogid(0) { }
|
||||
void Destroy()
|
||||
{
|
||||
glDeleteProgram(glprogid);
|
||||
glprogid = 0;
|
||||
}
|
||||
GLuint glprogid; // opengl program id
|
||||
|
||||
std::string strvprog, strpprog;
|
||||
GLint UniformLocations[NUM_UNIFORMS];
|
||||
|
||||
void SetProgramVariables();
|
||||
void SetProgramBindings();
|
||||
void Bind();
|
||||
};
|
||||
|
||||
class ProgramShaderCache
|
||||
{
|
||||
public:
|
||||
|
||||
struct PCacheEntry
|
||||
{
|
||||
SHADER shader;
|
||||
bool in_cache;
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
shader.Destroy();
|
||||
}
|
||||
};
|
||||
|
||||
static PCacheEntry GetShaderProgram(void);
|
||||
static GLuint GetCurrentProgram(void);
|
||||
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 GLuint CompileSingleShader(GLuint type, const char *code);
|
||||
|
||||
static void SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count);
|
||||
static void SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count);
|
||||
static void UploadConstants();
|
||||
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
static void CreateHeader(void);
|
||||
|
||||
private:
|
||||
class ProgramShaderCacheInserter : public LinearDiskCacheReader<SHADERUID, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const SHADERUID &key, const u8 *value, u32 value_size);
|
||||
};
|
||||
|
||||
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
||||
|
||||
static PCache pshaders;
|
||||
static PCacheEntry* last_entry;
|
||||
static SHADERUID last_uid;
|
||||
|
||||
static GLintptr s_vs_data_size;
|
||||
static GLintptr s_ps_data_size;
|
||||
static GLintptr s_vs_data_offset;
|
||||
static u8 *s_ubo_buffer;
|
||||
static u32 s_ubo_buffer_size;
|
||||
static bool s_ubo_dirty;
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
#endif
|
@ -17,12 +17,18 @@
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "RasterFont.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
// globals
|
||||
|
||||
const GLubyte rasters[][13] = {
|
||||
namespace OGL {
|
||||
|
||||
static const u32 char_width = 8;
|
||||
static const u32 char_height = 13;
|
||||
static const u32 char_offset = 32;
|
||||
static const u32 char_count = 95;
|
||||
|
||||
const u8 rasters[char_count][char_height] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
|
||||
@ -120,104 +126,159 @@ const GLubyte rasters[][13] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
|
||||
};
|
||||
|
||||
static const char *s_vertexShaderSrc =
|
||||
"uniform vec2 charSize;\n"
|
||||
"in vec2 rawpos;\n"
|
||||
"in vec2 tex0;\n"
|
||||
"out vec2 uv0;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
" uv0 = tex0 * charSize;\n"
|
||||
"}\n";
|
||||
|
||||
static const char *s_fragmentShaderSrc =
|
||||
"uniform sampler2D samp8;\n"
|
||||
"uniform vec4 color;\n"
|
||||
"in vec2 uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"void main(void) {\n"
|
||||
" ocol0 = texture(samp8,uv0) * color;\n"
|
||||
"}\n";
|
||||
|
||||
static SHADER s_shader;
|
||||
|
||||
RasterFont::RasterFont()
|
||||
{
|
||||
// set GL modes
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
// create the raster font
|
||||
fontOffset = glGenLists(128);
|
||||
for (int i = 32; i < 127; i++) {
|
||||
glNewList(i + fontOffset, GL_COMPILE);
|
||||
glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i - 32]);
|
||||
glEndList();
|
||||
// generate the texture
|
||||
glGenTextures(1, &texture);
|
||||
glActiveTexture(GL_TEXTURE0+8);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
u32* texture_data = new u32[char_width*char_count*char_height];
|
||||
for(u32 y=0; y<char_height; y++) {
|
||||
for(u32 c=0; c<char_count; c++) {
|
||||
for(u32 x=0; x<char_width; x++) {
|
||||
bool pixel = rasters[c][y] & (1<<(char_width-x-1));
|
||||
texture_data[char_width*char_count*y+char_width*c+x] = pixel ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp_buffer = new char[TEMP_BUFFER_SIZE];
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, char_width*char_count, char_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||
delete [] texture_data;
|
||||
|
||||
// generate shader
|
||||
ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc);
|
||||
|
||||
// bound uniforms
|
||||
glUniform2f(glGetUniformLocation(s_shader.glprogid,"charSize"), 1.0f / GLfloat(char_count), 1.0f);
|
||||
uniform_color_id = glGetUniformLocation(s_shader.glprogid,"color");
|
||||
glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
cached_color = -1;
|
||||
|
||||
// generate VBO & VAO
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBindVertexArray(VAO);
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
}
|
||||
|
||||
RasterFont::~RasterFont()
|
||||
{
|
||||
glDeleteLists(fontOffset, 128);
|
||||
delete [] temp_buffer;
|
||||
glDeleteTextures(1, &texture);
|
||||
glDeleteBuffers(1, &VBO);
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
s_shader.Destroy();
|
||||
}
|
||||
|
||||
void RasterFont::printString(const char *s, double x, double y, double z)
|
||||
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight, u32 color)
|
||||
{
|
||||
int length = (int)strlen(s);
|
||||
if (!length)
|
||||
return;
|
||||
if (length >= TEMP_BUFFER_SIZE)
|
||||
length = TEMP_BUFFER_SIZE - 1;
|
||||
|
||||
// Sanitize string to avoid GL errors.
|
||||
char *s2 = temp_buffer;
|
||||
memcpy(s2, s, length);
|
||||
s2[length] = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (s2[i] < 32 || s2[i] > 126)
|
||||
s2[i] = '!';
|
||||
}
|
||||
|
||||
// go to the right spot
|
||||
glRasterPos3d(x, y, z);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glPushAttrib (GL_LIST_BIT);
|
||||
glListBase(fontOffset);
|
||||
glCallLists((GLsizei)strlen(s2), GL_UNSIGNED_BYTE, (GLubyte *) s2);
|
||||
GL_REPORT_ERRORD();
|
||||
glPopAttrib();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z)
|
||||
{
|
||||
int length = (int)strlen(s);
|
||||
int x = (int)(screen_width/2.0 - (length/2.0)*char_width);
|
||||
printString(s, x, y, z);
|
||||
}
|
||||
|
||||
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight)
|
||||
{
|
||||
double x = start_x;
|
||||
double y = start_y;
|
||||
char temp[1024];
|
||||
char *t = temp;
|
||||
while (*text)
|
||||
{
|
||||
if (*text == '\n')
|
||||
{
|
||||
*t = 0;
|
||||
printString(temp, x, y, z);
|
||||
y -= char_height * 2.0f / bbHeight;
|
||||
size_t length = strlen(text);
|
||||
GLfloat *vertices = new GLfloat[length*6*4];
|
||||
|
||||
int usage = 0;
|
||||
GLfloat delta_x = GLfloat(2*char_width)/GLfloat(bbWidth);
|
||||
GLfloat delta_y = GLfloat(2*char_height)/GLfloat(bbHeight);
|
||||
GLfloat border_x = 2.0/GLfloat(bbWidth);
|
||||
GLfloat border_y = 4.0/GLfloat(bbHeight);
|
||||
|
||||
GLfloat x = GLfloat(start_x);
|
||||
GLfloat y = GLfloat(start_y);
|
||||
|
||||
for(size_t i=0; i<length; i++) {
|
||||
u8 c = text[i];
|
||||
|
||||
if(c == '\n') {
|
||||
x = start_x;
|
||||
t = temp;
|
||||
y -= delta_y + border_y;
|
||||
continue;
|
||||
}
|
||||
else if (*text == '\r')
|
||||
{
|
||||
t = temp;
|
||||
|
||||
// do not print spaces, they can be skipped easyly
|
||||
if(c == ' ') {
|
||||
x += delta_x + border_x;
|
||||
continue;
|
||||
}
|
||||
else if (*text == '\t')
|
||||
{
|
||||
//todo: add tabs every something like 4*char_width
|
||||
*t = 0;
|
||||
int cpos = (int)strlen(temp);
|
||||
int newpos = (cpos + 4) & (~3);
|
||||
printString(temp, x, y, z);
|
||||
x = start_x + (char_width*newpos) * 2.0f / bbWidth;
|
||||
t = temp;
|
||||
*t++ = ' ';
|
||||
}
|
||||
else
|
||||
*t++ = *text;
|
||||
|
||||
text++;
|
||||
|
||||
if(c < char_offset || c >= char_count+char_offset) continue;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
x += delta_x + border_x;
|
||||
}
|
||||
|
||||
// ????
|
||||
if (t != text)
|
||||
{
|
||||
*t = 0;
|
||||
printString(temp, x, y, z);
|
||||
|
||||
if(!usage) {
|
||||
delete [] vertices;
|
||||
return;
|
||||
}
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, usage*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
delete [] vertices;
|
||||
|
||||
s_shader.Bind();
|
||||
|
||||
if(color != cached_color) {
|
||||
glUniform4f(uniform_color_id, GLfloat((color>>16)&0xff)/255.f,GLfloat((color>>8)&0xff)/255.f,GLfloat((color>>0)&0xff)/255.f,GLfloat((color>>24)&0xff)/255.f);
|
||||
cached_color = color;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+8);
|
||||
glDrawArrays(GL_TRIANGLES, 0, usage/4);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,25 +18,24 @@
|
||||
#ifndef _RASTERFONT_H_
|
||||
#define _RASTERFONT_H_
|
||||
|
||||
namespace OGL {
|
||||
|
||||
class RasterFont {
|
||||
public:
|
||||
RasterFont();
|
||||
~RasterFont(void);
|
||||
static int debug;
|
||||
|
||||
// some useful constants
|
||||
enum {char_width = 10};
|
||||
enum {char_height = 15};
|
||||
|
||||
// and the happy helper functions
|
||||
void printString(const char *s, double x, double y, double z=0.0);
|
||||
void printCenteredString(const char *s, double y, int screen_width, double z=0.0);
|
||||
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight);
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight, u32 color);
|
||||
private:
|
||||
int fontOffset;
|
||||
char *temp_buffer;
|
||||
enum {TEMP_BUFFER_SIZE = 64 * 1024};
|
||||
|
||||
u32 VBO;
|
||||
u32 VAO;
|
||||
u32 texture;
|
||||
u32 uniform_color_id;
|
||||
u32 cached_color;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _RASTERFONT_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,11 +9,30 @@ namespace OGL
|
||||
|
||||
void ClearEFBCache();
|
||||
|
||||
// ogl-only config, so not in VideoConfig.h
|
||||
extern struct VideoConfig {
|
||||
bool bSupportsGLSLCache;
|
||||
bool bSupportsGLPinnedMemory;
|
||||
bool bSupportsGLSync;
|
||||
bool bSupportsGLBaseVertex;
|
||||
bool bSupportCoverageMSAA;
|
||||
bool bSupportSampleShading;
|
||||
|
||||
const char *gl_vendor;
|
||||
const char *gl_renderer;
|
||||
const char* gl_version;
|
||||
|
||||
s32 max_samples;
|
||||
} g_ogl_config;
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
{
|
||||
public:
|
||||
Renderer();
|
||||
~Renderer();
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void SetColorMask();
|
||||
void SetBlendMode(bool forceUpdate);
|
||||
|
129
Source/Plugins/Plugin_VideoOGL/Src/SamplerCache.cpp
Normal file
129
Source/Plugins/Plugin_VideoOGL/Src/SamplerCache.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "SamplerCache.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
SamplerCache *g_sampler_cache;
|
||||
|
||||
SamplerCache::SamplerCache()
|
||||
: m_last_max_anisotropy()
|
||||
{}
|
||||
|
||||
SamplerCache::~SamplerCache()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1)
|
||||
{
|
||||
// TODO: can this go somewhere else?
|
||||
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
|
||||
{
|
||||
m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
||||
Clear();
|
||||
}
|
||||
|
||||
Params params(tm0, tm1);
|
||||
|
||||
// take equivalent forced linear when bForceFiltering
|
||||
if (g_ActiveConfig.bForceFiltering)
|
||||
{
|
||||
params.tm0.min_filter |= 0x4;
|
||||
params.tm0.mag_filter |= 0x1;
|
||||
}
|
||||
|
||||
// TODO: Should keep a circular buffer for each stage of recently used samplers.
|
||||
|
||||
auto& active_sampler = m_active_samplers[stage];
|
||||
if (active_sampler.first != params || !active_sampler.second.sampler_id)
|
||||
{
|
||||
// Active sampler does not match parameters (or is invalid), bind the proper one.
|
||||
active_sampler.first = params;
|
||||
active_sampler.second = GetEntry(params);
|
||||
glBindSampler(stage, active_sampler.second.sampler_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto SamplerCache::GetEntry(const Params& params) -> Value&
|
||||
{
|
||||
auto& val = m_cache[params];
|
||||
if (!val.sampler_id)
|
||||
{
|
||||
// Sampler not found in cache, create it.
|
||||
glGenSamplers(1, &val.sampler_id);
|
||||
SetParameters(val.sampler_id, params);
|
||||
|
||||
// TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though.
|
||||
//ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size());
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void SamplerCache::SetParameters(GLuint sampler_id, const Params& params)
|
||||
{
|
||||
static const GLint min_filters[8] =
|
||||
{
|
||||
GL_NEAREST,
|
||||
GL_NEAREST_MIPMAP_NEAREST,
|
||||
GL_NEAREST_MIPMAP_LINEAR,
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR_MIPMAP_NEAREST,
|
||||
GL_LINEAR_MIPMAP_LINEAR,
|
||||
GL_LINEAR,
|
||||
};
|
||||
|
||||
static const GLint wrap_settings[4] =
|
||||
{
|
||||
GL_CLAMP_TO_EDGE,
|
||||
GL_REPEAT,
|
||||
GL_MIRRORED_REPEAT,
|
||||
GL_REPEAT,
|
||||
};
|
||||
|
||||
auto& tm0 = params.tm0;
|
||||
auto& tm1 = params.tm1;
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filters[tm0.min_filter % ARRAYSIZE(min_filters)]);
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, tm0.mag_filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]);
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]);
|
||||
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, tm0.lod_bias / 32.f);
|
||||
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f);
|
||||
|
||||
if (g_ActiveConfig.iMaxAnisotropy > 0)
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||
}
|
||||
|
||||
void SamplerCache::Clear()
|
||||
{
|
||||
for (auto it = m_cache.begin(); it != m_cache.end(); ++it)
|
||||
{
|
||||
glDeleteSamplers(1, &it->second.sampler_id);
|
||||
}
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
}
|
80
Source/Plugins/Plugin_VideoOGL/Src/SamplerCache.h
Normal file
80
Source/Plugins/Plugin_VideoOGL/Src/SamplerCache.h
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
#ifndef INCLUDE_SAMPLER_CACHE_H_
|
||||
#define INCLUDE_SAMPLER_CACHE_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Render.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class SamplerCache : NonCopyable
|
||||
{
|
||||
public:
|
||||
SamplerCache();
|
||||
~SamplerCache();
|
||||
|
||||
void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
struct Params
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
TexMode0 tm0;
|
||||
TexMode1 tm1;
|
||||
};
|
||||
|
||||
u64 hex;
|
||||
};
|
||||
|
||||
Params()
|
||||
: hex()
|
||||
{}
|
||||
|
||||
Params(const TexMode0& _tm0, const TexMode1& _tm1)
|
||||
: tm0(_tm0)
|
||||
, tm1(_tm1)
|
||||
{
|
||||
static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int.");
|
||||
}
|
||||
|
||||
bool operator<(const Params& other) const
|
||||
{
|
||||
return hex < other.hex;
|
||||
}
|
||||
|
||||
bool operator!=(const Params& other) const
|
||||
{
|
||||
return hex != other.hex;
|
||||
}
|
||||
};
|
||||
|
||||
struct Value
|
||||
{
|
||||
Value()
|
||||
: sampler_id()
|
||||
{}
|
||||
|
||||
GLuint sampler_id;
|
||||
};
|
||||
|
||||
void SetParameters(GLuint sampler_id, const Params& params);
|
||||
Value& GetEntry(const Params& params);
|
||||
|
||||
std::map<Params, Value> m_cache;
|
||||
std::pair<Params, Value> m_active_samplers[8];
|
||||
|
||||
int m_last_max_anisotropy;
|
||||
};
|
||||
|
||||
extern SamplerCache *g_sampler_cache;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
242
Source/Plugins/Plugin_VideoOGL/Src/StreamBuffer.cpp
Normal file
242
Source/Plugins/Plugin_VideoOGL/Src/StreamBuffer.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Globals.h"
|
||||
#include "GLUtil.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Render.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static const u32 SYNC_POINTS = 16;
|
||||
static const u32 ALIGN_PINNED_MEMORY = 4096;
|
||||
|
||||
StreamBuffer::StreamBuffer(u32 type, size_t size, StreamType uploadType)
|
||||
: m_uploadtype(uploadType), m_buffertype(type), m_size(size)
|
||||
{
|
||||
glGenBuffers(1, &m_buffer);
|
||||
|
||||
bool nvidia = !strcmp(g_ogl_config.gl_vendor, "NVIDIA Corporation");
|
||||
|
||||
if(m_uploadtype & STREAM_DETECT)
|
||||
{
|
||||
if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERSUBDATA))
|
||||
m_uploadtype = BUFFERSUBDATA;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_Config.bHackedBufferUpload && (m_uploadtype & MAP_AND_RISK))
|
||||
m_uploadtype = MAP_AND_RISK;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && (m_uploadtype & PINNED_MEMORY))
|
||||
m_uploadtype = PINNED_MEMORY;
|
||||
else if(nvidia && (m_uploadtype & BUFFERSUBDATA))
|
||||
m_uploadtype = BUFFERSUBDATA;
|
||||
else if(g_ogl_config.bSupportsGLSync && (m_uploadtype & MAP_AND_SYNC))
|
||||
m_uploadtype = MAP_AND_SYNC;
|
||||
else
|
||||
m_uploadtype = MAP_AND_ORPHAN;
|
||||
}
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
StreamBuffer::~StreamBuffer()
|
||||
{
|
||||
Shutdown();
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
#define SLOT(x) (x)*SYNC_POINTS/m_size
|
||||
|
||||
void StreamBuffer::Alloc ( size_t size, u32 stride )
|
||||
{
|
||||
size_t m_iterator_aligned = m_iterator;
|
||||
if(m_iterator_aligned && stride) {
|
||||
m_iterator_aligned--;
|
||||
m_iterator_aligned = m_iterator_aligned - (m_iterator_aligned % stride) + stride;
|
||||
}
|
||||
size_t iter_end = m_iterator_aligned + size;
|
||||
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_ORPHAN:
|
||||
if(iter_end >= m_size) {
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
m_iterator_aligned = 0;
|
||||
}
|
||||
break;
|
||||
case MAP_AND_SYNC:
|
||||
case PINNED_MEMORY:
|
||||
|
||||
// insert waiting slots for used memory
|
||||
for(u32 i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
|
||||
{
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
m_used_iterator = m_iterator;
|
||||
|
||||
// wait for new slots to end of buffer
|
||||
for(u32 i=SLOT(m_free_iterator)+1; i<=SLOT(iter_end) && i < SYNC_POINTS; i++)
|
||||
{
|
||||
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fences[i]);
|
||||
}
|
||||
m_free_iterator = iter_end;
|
||||
|
||||
// if buffer is full
|
||||
if(iter_end >= m_size) {
|
||||
|
||||
// insert waiting slots in unused space at the end of the buffer
|
||||
for(u32 i=SLOT(m_used_iterator); i < SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
// move to the start
|
||||
m_used_iterator = m_iterator_aligned = m_iterator = 0; // offset 0 is always aligned
|
||||
iter_end = size;
|
||||
|
||||
// wait for space at the start
|
||||
for(u32 i=0; i<=SLOT(iter_end); i++)
|
||||
{
|
||||
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fences[i]);
|
||||
}
|
||||
m_free_iterator = iter_end;
|
||||
}
|
||||
|
||||
break;
|
||||
case MAP_AND_RISK:
|
||||
if(iter_end >= m_size) {
|
||||
m_iterator_aligned = 0;
|
||||
}
|
||||
break;
|
||||
case BUFFERSUBDATA:
|
||||
m_iterator_aligned = 0;
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
m_iterator = m_iterator_aligned;
|
||||
}
|
||||
|
||||
size_t StreamBuffer::Upload ( u8* data, size_t size )
|
||||
{
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
case MAP_AND_ORPHAN:
|
||||
pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
if(pointer) {
|
||||
memcpy(pointer, data, size);
|
||||
glUnmapBuffer(m_buffertype);
|
||||
} else {
|
||||
ERROR_LOG(VIDEO, "buffer mapping failed");
|
||||
}
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
case MAP_AND_RISK:
|
||||
if(pointer)
|
||||
memcpy(pointer+m_iterator, data, size);
|
||||
break;
|
||||
case BUFFERSUBDATA:
|
||||
glBufferSubData(m_buffertype, m_iterator, size, data);
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
size_t ret = m_iterator;
|
||||
m_iterator += size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void StreamBuffer::Init()
|
||||
{
|
||||
m_iterator = 0;
|
||||
m_used_iterator = 0;
|
||||
m_free_iterator = 0;
|
||||
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
fences = new GLsync[SYNC_POINTS];
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
case MAP_AND_ORPHAN:
|
||||
case BUFFERSUBDATA:
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
glGetError(); // errors before this allocation should be ignored
|
||||
fences = new GLsync[SYNC_POINTS];
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
pointer = (u8*)AllocateAlignedMemory(ROUND_UP(m_size,ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY );
|
||||
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer);
|
||||
glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size,ALIGN_PINNED_MEMORY), pointer, GL_STREAM_COPY);
|
||||
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
|
||||
// on error, switch to another backend. some old catalyst seems to have broken pinned memory support
|
||||
if(glGetError() != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "pinned memory detected, but not working. Please report this: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version);
|
||||
Shutdown();
|
||||
m_uploadtype = MAP_AND_SYNC;
|
||||
Init();
|
||||
}
|
||||
break;
|
||||
case MAP_AND_RISK:
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
pointer = (u8*)glMapBuffer(m_buffertype, GL_WRITE_ONLY);
|
||||
glUnmapBuffer(m_buffertype);
|
||||
if(!pointer)
|
||||
ERROR_LOG(VIDEO, "buffer allocation failed");
|
||||
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void StreamBuffer::Shutdown()
|
||||
{
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
glDeleteSync(fences[i]);
|
||||
delete [] fences;
|
||||
break;
|
||||
|
||||
case MAP_AND_RISK:
|
||||
case MAP_AND_ORPHAN:
|
||||
case BUFFERSUBDATA:
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
glDeleteSync(fences[i]);
|
||||
delete [] fences;
|
||||
glBindBuffer(m_buffertype, 0);
|
||||
glFinish(); // ogl pipeline must be flushed, else this buffer can be in use
|
||||
FreeAlignedMemory(pointer);
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
72
Source/Plugins/Plugin_VideoOGL/Src/StreamBuffer.h
Normal file
72
Source/Plugins/Plugin_VideoOGL/Src/StreamBuffer.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
#ifndef STREAMBUFFER_H
|
||||
#define STREAMBUFFER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
// glew < 1.8 doesn't support pinned memory
|
||||
#ifndef GLEW_AMD_pinned_memory
|
||||
#define GLEW_AMD_pinned_memory glewIsSupported("GL_AMD_pinned_memory")
|
||||
#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
|
||||
#endif
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
enum StreamType {
|
||||
DETECT_MASK = 0x1F,
|
||||
STREAM_DETECT = (1 << 0),
|
||||
MAP_AND_ORPHAN = (1 << 1),
|
||||
MAP_AND_SYNC = (1 << 2),
|
||||
MAP_AND_RISK = (1 << 3),
|
||||
PINNED_MEMORY = (1 << 4),
|
||||
BUFFERSUBDATA = (1 << 5)
|
||||
};
|
||||
|
||||
class StreamBuffer {
|
||||
|
||||
public:
|
||||
StreamBuffer(u32 type, size_t size, StreamType uploadType = DETECT_MASK);
|
||||
~StreamBuffer();
|
||||
|
||||
void Alloc(size_t size, u32 stride = 0);
|
||||
size_t Upload(u8 *data, size_t size);
|
||||
|
||||
u32 getBuffer() { return m_buffer; }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
StreamType m_uploadtype;
|
||||
u32 m_buffer;
|
||||
u32 m_buffertype;
|
||||
size_t m_size;
|
||||
u8 *pointer;
|
||||
size_t m_iterator;
|
||||
size_t m_used_iterator;
|
||||
size_t m_free_iterator;
|
||||
GLsync *fences;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STREAMBUFFER_H
|
@ -42,7 +42,7 @@
|
||||
#include "HW/Memmap.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "Render.h"
|
||||
#include "Statistics.h"
|
||||
@ -56,33 +56,36 @@
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static SHADER s_ColorMatrixProgram;
|
||||
static SHADER s_DepthMatrixProgram;
|
||||
static GLuint s_ColorMatrixUniform;
|
||||
static GLuint s_DepthMatrixUniform;
|
||||
static u32 s_ColorCbufid;
|
||||
static u32 s_DepthCbufid;
|
||||
|
||||
static u32 s_Textures[8];
|
||||
static u32 s_ActiveTexture;
|
||||
static u32 s_NextStage;
|
||||
|
||||
struct VBOCache {
|
||||
GLuint vbo;
|
||||
GLuint vao;
|
||||
TargetRectangle targetSource;
|
||||
};
|
||||
static std::map<u64,VBOCache> s_VBO;
|
||||
|
||||
static u32 s_TempFramebuffer = 0;
|
||||
|
||||
static const GLint c_MinLinearFilter[8] = {
|
||||
GL_NEAREST,
|
||||
GL_NEAREST_MIPMAP_NEAREST,
|
||||
GL_NEAREST_MIPMAP_LINEAR,
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR_MIPMAP_NEAREST,
|
||||
GL_LINEAR_MIPMAP_LINEAR,
|
||||
GL_LINEAR,
|
||||
};
|
||||
|
||||
static const GLint c_WrapSettings[4] = {
|
||||
GL_CLAMP_TO_EDGE,
|
||||
GL_REPEAT,
|
||||
GL_MIRRORED_REPEAT,
|
||||
GL_REPEAT,
|
||||
};
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
|
||||
{
|
||||
int width = std::max(virtual_width >> level, 1);
|
||||
int height = std::max(virtual_height >> level, 1);
|
||||
std::vector<u32> data(width * height);
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(textarget, tex);
|
||||
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
glBindTexture(textarget, 0);
|
||||
TextureCache::SetStage();
|
||||
|
||||
const GLenum err = GL_REPORT_ERROR();
|
||||
if (GL_NO_ERROR != err)
|
||||
@ -98,6 +101,9 @@ TextureCache::TCacheEntry::~TCacheEntry()
|
||||
{
|
||||
if (texture)
|
||||
{
|
||||
for(int i=0; i<8; i++)
|
||||
if(s_Textures[i] == texture)
|
||||
s_Textures[i] = 0;
|
||||
glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
@ -111,14 +117,17 @@ TextureCache::TCacheEntry::TCacheEntry()
|
||||
|
||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
{
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// TODO: is this already done somewhere else?
|
||||
TexMode0 &tm0 = bpmem.tex[stage >> 2].texMode0[stage & 3];
|
||||
TexMode1 &tm1 = bpmem.tex[stage >> 2].texMode1[stage & 3];
|
||||
SetTextureParameters(tm0, tm1);
|
||||
if (s_Textures[stage] != texture)
|
||||
{
|
||||
if (s_ActiveTexture != stage)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + stage);
|
||||
s_ActiveTexture = stage;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
s_Textures[stage] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
@ -147,13 +156,13 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
PanicAlert("Invalid PC texture format %i", pcfmt);
|
||||
case PC_TEX_FMT_BGRA32:
|
||||
gl_format = GL_BGRA;
|
||||
gl_iformat = 4;
|
||||
gl_iformat = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case PC_TEX_FMT_RGBA32:
|
||||
gl_format = GL_RGBA;
|
||||
gl_iformat = 4;
|
||||
gl_iformat = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
@ -195,36 +204,43 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
entry.gl_type = gl_type;
|
||||
entry.pcfmt = pcfmt;
|
||||
|
||||
entry.bHaveMipMaps = tex_levels != 1;
|
||||
entry.m_tex_levels = tex_levels;
|
||||
|
||||
entry.Load(width, height, expanded_width, 0);
|
||||
|
||||
return &entry;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level, bool autogen_mips)
|
||||
unsigned int expanded_width, unsigned int level)
|
||||
{
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
//GL_REPORT_ERRORD();
|
||||
if (s_ActiveTexture != s_NextStage)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + s_NextStage);
|
||||
s_ActiveTexture = s_NextStage;
|
||||
}
|
||||
|
||||
if (s_Textures[s_NextStage] != texture)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
s_Textures[s_NextStage] = texture;
|
||||
}
|
||||
|
||||
// TODO: sloppy, just do this on creation?
|
||||
if (level == 0)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m_tex_levels - 1);
|
||||
}
|
||||
|
||||
if (pcfmt != PC_TEX_FMT_DXT1)
|
||||
{
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
|
||||
|
||||
if (bHaveMipMaps && autogen_mips)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
|
||||
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -239,31 +255,26 @@ TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
|
||||
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
|
||||
{
|
||||
TCacheEntry *const entry = new TCacheEntry;
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, entry->texture);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
const GLenum
|
||||
gl_format = GL_RGBA,
|
||||
gl_iformat = 4,
|
||||
gl_iformat = GL_RGBA,
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
entry->m_tex_levels = 1;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_h, 0, gl_format, gl_type, NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
SetStage();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -272,8 +283,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// Make sure to resolve anything we need to read from.
|
||||
const GLuint read_texture = (srcFormat == PIXELFMT_Z24) ?
|
||||
FramebufferManager::ResolveAndGetDepthTarget(srcRect) :
|
||||
@ -284,38 +295,85 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
if (s_TempFramebuffer == 0)
|
||||
glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
glGenFramebuffers(1, (GLuint*)&s_TempFramebuffer);
|
||||
|
||||
FramebufferManager::SetFramebuffer(s_TempFramebuffer);
|
||||
// Bind texture to temporary framebuffer
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
GL_REPORT_FBO_ERROR();
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, read_texture);
|
||||
|
||||
glViewport(0, 0, virtual_width, virtual_height);
|
||||
|
||||
PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
|
||||
PixelShaderManager::SetColorMatrix(colmat); // set transformation
|
||||
if(srcFormat == PIXELFMT_Z24) {
|
||||
s_DepthMatrixProgram.Bind();
|
||||
if(s_DepthCbufid != cbufid)
|
||||
glUniform4fv(s_DepthMatrixUniform, 5, colmat);
|
||||
s_DepthCbufid = cbufid;
|
||||
} else {
|
||||
s_ColorMatrixProgram.Bind();
|
||||
if(s_ColorCbufid != cbufid)
|
||||
glUniform4fv(s_ColorMatrixUniform, 7, colmat);
|
||||
s_ColorCbufid = cbufid;
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// should be unique enough, if not, vbo will "only" be uploaded to much
|
||||
u64 targetSourceHash = u64(targetSource.left)<<48 | u64(targetSource.top)<<32 | u64(targetSource.right)<<16 | u64(targetSource.bottom);
|
||||
std::map<u64, VBOCache>::iterator vbo_it = s_VBO.find(targetSourceHash);
|
||||
|
||||
if(vbo_it == s_VBO.end()) {
|
||||
VBOCache item;
|
||||
item.targetSource.bottom = -1;
|
||||
item.targetSource.top = -1;
|
||||
item.targetSource.left = -1;
|
||||
item.targetSource.right = -1;
|
||||
glGenBuffers(1, &item.vbo);
|
||||
glGenVertexArrays(1, &item.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, item.vbo);
|
||||
glBindVertexArray(item.vao);
|
||||
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
vbo_it = s_VBO.insert(std::pair<u64,VBOCache>(targetSourceHash, item)).first;
|
||||
}
|
||||
if(!(vbo_it->second.targetSource == targetSource)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, 1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.bottom,
|
||||
-1.f, -1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.top,
|
||||
1.f, -1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.top,
|
||||
1.f, 1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.bottom
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_it->second.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
vbo_it->second.targetSource = targetSource;
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1);
|
||||
glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1);
|
||||
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1);
|
||||
glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1);
|
||||
glEnd();
|
||||
glBindVertexArray(vbo_it->second.vao);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// Unbind texture from temporary framebuffer
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||
}
|
||||
|
||||
if (false == g_ActiveConfig.bCopyEFBToTexture)
|
||||
@ -330,20 +388,19 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
srcRect);
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
u64 hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
u64 const new_hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
else if (!TextureCache::Find(addr, new_hash))
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
|
||||
this->hash = hash;
|
||||
hash = new_hash;
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
DisableStage(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
@ -353,55 +410,97 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
|
||||
}
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1)
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
// TODO: not used anywhere
|
||||
TexMode0 mode = newmode;
|
||||
//mode1 = newmode1;
|
||||
const char *pColorMatrixProg =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"uniform vec4 colmat[7];\n"
|
||||
"in vec2 uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"\n"
|
||||
"void main(){\n"
|
||||
" vec4 texcol = texture2DRect(samp9, 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";
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
(newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
|
||||
const char *pDepthMatrixProg =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"uniform vec4 colmat[5];\n"
|
||||
"in vec2 uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"\n"
|
||||
"void main(){\n"
|
||||
" vec4 texcol = texture2DRect(samp9, uv0);\n"
|
||||
" vec4 EncodedDepth = fract((texcol.r * (16777215.0f/16777216.0f)) * vec4(1.0f,256.0f,256.0f*256.0f,1.0f));\n"
|
||||
" texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * vec4(255.0f,255.0f,255.0f,15.0f)) / vec4(255.0f,255.0f,255.0f,15.0f);\n"
|
||||
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];"
|
||||
"}\n";
|
||||
|
||||
if (bHaveMipMaps)
|
||||
{
|
||||
// TODO: not used anywhere
|
||||
if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4)
|
||||
mode.min_filter += 4; // take equivalent forced linear
|
||||
|
||||
int filt = newmode.min_filter;
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod >> 4);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod >> 4);
|
||||
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias / 32.0f));
|
||||
}
|
||||
else
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
(g_ActiveConfig.bForceFiltering || newmode.min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]);
|
||||
|
||||
if (g_Config.iMaxAnisotropy >= 1)
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
(float)(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||
|
||||
const char *VProgram =
|
||||
"in vec2 rawpos;\n"
|
||||
"in vec2 tex0;\n"
|
||||
"out vec2 uv0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" uv0 = tex0;\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, VProgram, pColorMatrixProg);
|
||||
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, VProgram, pDepthMatrixProg);
|
||||
|
||||
s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat");
|
||||
s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat");
|
||||
s_ColorCbufid = -1;
|
||||
s_DepthCbufid = -1;
|
||||
|
||||
s_ActiveTexture = -1;
|
||||
s_NextStage = -1;
|
||||
for(int i=0; i<8; i++)
|
||||
s_Textures[i] = -1;
|
||||
}
|
||||
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
if (s_TempFramebuffer)
|
||||
s_ColorMatrixProgram.Destroy();
|
||||
s_DepthMatrixProgram.Destroy();
|
||||
|
||||
for(std::map<u64, VBOCache>::iterator it = s_VBO.begin(); it != s_VBO.end(); it++) {
|
||||
glDeleteBuffers(1, &it->second.vbo);
|
||||
glDeleteVertexArrays(1, &it->second.vao);
|
||||
}
|
||||
s_VBO.clear();
|
||||
|
||||
if (s_TempFramebuffer)
|
||||
{
|
||||
glDeleteFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
|
||||
s_TempFramebuffer = 0;
|
||||
}
|
||||
glDeleteFramebuffers(1, (GLuint*)&s_TempFramebuffer);
|
||||
s_TempFramebuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::DisableStage(unsigned int stage)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + stage);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
}
|
||||
|
||||
void TextureCache::SetStage ()
|
||||
{
|
||||
// -1 is the initial value as we don't know which testure should be bound
|
||||
if(s_ActiveTexture != (u32)-1)
|
||||
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
|
||||
}
|
||||
|
||||
void TextureCache::SetNextStage ( unsigned int stage )
|
||||
{
|
||||
s_NextStage = stage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -32,7 +32,10 @@ namespace OGL
|
||||
class TextureCache : public ::TextureCache
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
static void DisableStage(unsigned int stage);
|
||||
static void SetStage();
|
||||
static void SetNextStage(unsigned int stage);
|
||||
|
||||
private:
|
||||
struct TCacheEntry : TCacheEntryBase
|
||||
@ -45,7 +48,7 @@ private:
|
||||
int gl_iformat;
|
||||
int gl_type;
|
||||
|
||||
bool bHaveMipMaps;
|
||||
int m_tex_levels;
|
||||
|
||||
//TexMode0 mode; // current filter and clamp modes that texture is set to
|
||||
//TexMode1 mode1; // current filter and clamp modes that texture is set to
|
||||
@ -54,7 +57,7 @@ private:
|
||||
~TCacheEntry();
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level, bool autogen_mips = false);
|
||||
unsigned int expanded_width, unsigned int level);
|
||||
|
||||
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
@ -63,9 +66,6 @@ private:
|
||||
|
||||
void Bind(unsigned int stage);
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
|
||||
private:
|
||||
void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1);
|
||||
};
|
||||
|
||||
~TextureCache();
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "TextureConverter.h"
|
||||
#include "TextureConversionShader.h"
|
||||
#include "TextureCache.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "Globals.h"
|
||||
@ -50,64 +50,73 @@ static GLuint s_dstRenderBuffer = 0; // for encoding to RAM
|
||||
const int renderBufferWidth = 1024;
|
||||
const int renderBufferHeight = 1024;
|
||||
|
||||
static FRAGMENTSHADER s_rgbToYuyvProgram;
|
||||
static FRAGMENTSHADER s_yuyvToRgbProgram;
|
||||
static SHADER s_rgbToYuyvProgram;
|
||||
static SHADER s_yuyvToRgbProgram;
|
||||
|
||||
// Not all slots are taken - but who cares.
|
||||
const u32 NUM_ENCODING_PROGRAMS = 64;
|
||||
static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
||||
static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
||||
|
||||
void CreateRgbToYuyvProgram()
|
||||
static GLuint s_encode_VBO = 0;
|
||||
static GLuint s_encode_VAO = 0;
|
||||
static GLuint s_decode_VBO = 0;
|
||||
static GLuint s_decode_VAO = 0;
|
||||
static TargetRectangle s_cached_sourceRc;
|
||||
static int s_cached_srcWidth = 0;
|
||||
static int s_cached_srcHeight = 0;
|
||||
|
||||
static const char *VProgram =
|
||||
"in vec2 rawpos;\n"
|
||||
"in vec2 tex0;\n"
|
||||
"out vec2 uv0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" uv0 = tex0;\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
void CreatePrograms()
|
||||
{
|
||||
// Output is BGRA because that is slightly faster than RGBA.
|
||||
const char *FProgram =
|
||||
"uniform samplerRECT samp0 : register(s0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : COLOR0,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" float2 uv1 = float2(uv0.x + 1.0f, uv0.y);\n"
|
||||
" float3 c0 = texRECT(samp0, uv0).rgb;\n"
|
||||
" float3 c1 = texRECT(samp0, uv1).rgb;\n"
|
||||
" float3 y_const = float3(0.257f,0.504f,0.098f);\n"
|
||||
" float3 u_const = float3(-0.148f,-0.291f,0.439f);\n"
|
||||
" float3 v_const = float3(0.439f,-0.368f,-0.071f);\n"
|
||||
" float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n"
|
||||
" float3 c01 = (c0 + c1) * 0.5f;\n"
|
||||
" ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n"
|
||||
"}\n";
|
||||
const char *FProgramRgbToYuyv =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"in vec2 uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec3 c0 = texture2DRect(samp9, uv0).rgb;\n"
|
||||
" vec3 c1 = texture2DRect(samp9, uv0 + vec2(1.0, 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"
|
||||
" vec3 v_const = vec3(0.439,-0.368,-0.071);\n"
|
||||
" vec4 const3 = vec4(0.0625,0.5,0.0625f,0.5);\n"
|
||||
" ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n"
|
||||
"}\n";
|
||||
|
||||
if (!PixelShaderCache::CompilePixelShader(s_rgbToYuyvProgram, FProgram))
|
||||
ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program.");
|
||||
const char *FProgramYuyvToRgb =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"in vec2 uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 c0 = texture2DRect(samp9, uv0).rgba;\n"
|
||||
" float f = step(0.5, fract(uv0.x));\n"
|
||||
" float y = mix(c0.b, c0.r, f);\n"
|
||||
" float yComp = 1.164f * (y - 0.0625f);\n"
|
||||
" float uComp = c0.g - 0.5f;\n"
|
||||
" float vComp = c0.a - 0.5f;\n"
|
||||
" ocol0 = vec4(yComp + (1.596f * vComp),\n"
|
||||
" yComp - (0.813f * vComp) - (0.391f * uComp),\n"
|
||||
" yComp + (2.018f * uComp),\n"
|
||||
" 1.0f);\n"
|
||||
"}\n";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgram, FProgramRgbToYuyv);
|
||||
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgram, FProgramYuyvToRgb);
|
||||
}
|
||||
|
||||
void CreateYuyvToRgbProgram()
|
||||
{
|
||||
const char *FProgram =
|
||||
"uniform samplerRECT samp0 : register(s0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : COLOR0,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" float4 c0 = texRECT(samp0, uv0).rgba;\n"
|
||||
|
||||
" float f = step(0.5, frac(uv0.x));\n"
|
||||
" float y = lerp(c0.b, c0.r, f);\n"
|
||||
" float yComp = 1.164f * (y - 0.0625f);\n"
|
||||
" float uComp = c0.g - 0.5f;\n"
|
||||
" float vComp = c0.a - 0.5f;\n"
|
||||
|
||||
" ocol0 = float4(yComp + (1.596f * vComp),\n"
|
||||
" yComp - (0.813f * vComp) - (0.391f * uComp),\n"
|
||||
" yComp + (2.018f * uComp),\n"
|
||||
" 1.0f);\n"
|
||||
"}\n";
|
||||
|
||||
if (!PixelShaderCache::CompilePixelShader(s_yuyvToRgbProgram, FProgram))
|
||||
ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program.");
|
||||
}
|
||||
|
||||
FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
|
||||
SHADER &GetOrCreateEncodingShader(u32 format)
|
||||
{
|
||||
if (format > NUM_ENCODING_PROGRAMS)
|
||||
{
|
||||
@ -117,7 +126,7 @@ FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
|
||||
|
||||
if (s_encodingPrograms[format].glprogid == 0)
|
||||
{
|
||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_OPENGL);
|
||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_OPENGL);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
|
||||
@ -130,20 +139,43 @@ FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!PixelShaderCache::CompilePixelShader(s_encodingPrograms[format], shader)) {
|
||||
ERROR_LOG(VIDEO, "Failed to create encoding fragment program");
|
||||
}
|
||||
ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader);
|
||||
}
|
||||
return s_encodingPrograms[format];
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
glGenFramebuffersEXT(1, &s_texConvFrameBuffer);
|
||||
glGenFramebuffers(1, &s_texConvFrameBuffer);
|
||||
|
||||
glGenBuffers(1, &s_encode_VBO );
|
||||
glGenVertexArrays(1, &s_encode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
s_cached_sourceRc.top = -1;
|
||||
s_cached_sourceRc.bottom = -1;
|
||||
s_cached_sourceRc.left = -1;
|
||||
s_cached_sourceRc.right = -1;
|
||||
|
||||
glGenBuffers(1, &s_decode_VBO );
|
||||
glGenVertexArrays(1, &s_decode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
s_cached_srcWidth = -1;
|
||||
s_cached_srcHeight = -1;
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
glGenRenderbuffersEXT(1, &s_dstRenderBuffer);
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight);
|
||||
glGenRenderbuffers(1, &s_dstRenderBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, s_dstRenderBuffer);
|
||||
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, renderBufferWidth, renderBufferHeight);
|
||||
|
||||
s_srcTextureWidth = 0;
|
||||
s_srcTextureHeight = 0;
|
||||
@ -152,16 +184,20 @@ void Init()
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
CreateRgbToYuyvProgram();
|
||||
CreateYuyvToRgbProgram();
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
CreatePrograms();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
glDeleteTextures(1, &s_srcTexture);
|
||||
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
|
||||
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
|
||||
glDeleteRenderbuffers(1, &s_dstRenderBuffer);
|
||||
glDeleteFramebuffers(1, &s_texConvFrameBuffer);
|
||||
glDeleteBuffers(1, &s_encode_VBO );
|
||||
glDeleteVertexArrays(1, &s_encode_VAO );
|
||||
glDeleteBuffers(1, &s_decode_VBO );
|
||||
glDeleteVertexArrays(1, &s_decode_VAO );
|
||||
|
||||
s_rgbToYuyvProgram.Destroy();
|
||||
s_yuyvToRgbProgram.Destroy();
|
||||
@ -174,8 +210,8 @@ void Shutdown()
|
||||
s_texConvFrameBuffer = 0;
|
||||
}
|
||||
|
||||
void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight, int readStride,
|
||||
void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight, int readStride,
|
||||
bool toTexture, bool linearFilter)
|
||||
{
|
||||
|
||||
@ -184,42 +220,52 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
|
||||
// attach render buffer as color destination
|
||||
FramebufferManager::SetFramebuffer(s_texConvFrameBuffer);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, s_dstRenderBuffer);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, s_dstRenderBuffer);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
for (int i = 1; i < 8; ++i)
|
||||
TextureCache::DisableStage(i);
|
||||
|
||||
// set source texture
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture);
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, srcTexture);
|
||||
|
||||
if (linearFilter)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);
|
||||
|
||||
PixelShaderCache::SetCurrentShader(shader.glprogid);
|
||||
GL_REPORT_ERRORD();
|
||||
if(!(s_cached_sourceRc == sourceRc)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, -1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.top,
|
||||
-1.f, 1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.bottom,
|
||||
1.f, 1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.bottom,
|
||||
1.f, -1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.top
|
||||
};
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
s_cached_sourceRc = sourceRc;
|
||||
}
|
||||
|
||||
// Draw...
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((float)sourceRc.left, (float)sourceRc.top); glVertex2f(-1,-1);
|
||||
glTexCoord2f((float)sourceRc.left, (float)sourceRc.bottom); glVertex2f(-1,1);
|
||||
glTexCoord2f((float)sourceRc.right, (float)sourceRc.bottom); glVertex2f(1,1);
|
||||
glTexCoord2f((float)sourceRc.right, (float)sourceRc.top); glVertex2f(1,-1);
|
||||
glEnd();
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// .. and then read back the results.
|
||||
@ -266,9 +312,7 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
||||
format |= _GX_TF_CTF;
|
||||
|
||||
FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format);
|
||||
if (texconv_shader.glprogid == 0)
|
||||
return 0;
|
||||
SHADER& texconv_shader = GetOrCreateEncodingShader(format);
|
||||
|
||||
u8 *dest_ptr = Memory::GetPointer(address);
|
||||
|
||||
@ -285,14 +329,18 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
||||
// extra pixels are copied but not displayed in the resulting texture
|
||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
||||
|
||||
|
||||
float sampleStride = bScaleByHalf ? 2.f : 1.f;
|
||||
TextureConversionShader::SetShaderParameters((float)expandedWidth,
|
||||
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
|
||||
(float)Renderer::EFBToScaledX(source.left),
|
||||
(float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight),
|
||||
Renderer::EFBToScaledXf(sampleStride),
|
||||
Renderer::EFBToScaledYf(sampleStride));
|
||||
|
||||
float params[] = {
|
||||
Renderer::EFBToScaledXf(sampleStride), Renderer::EFBToScaledYf(sampleStride),
|
||||
0.0f, 0.0f,
|
||||
(float)expandedWidth, (float)Renderer::EFBToScaledY(expandedHeight)-1,
|
||||
(float)Renderer::EFBToScaledX(source.left), (float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight)
|
||||
};
|
||||
|
||||
texconv_shader.Bind();
|
||||
glUniform4fv(texconv_shader.UniformLocations[C_COLORS], 2, params);
|
||||
|
||||
TargetRectangle scaledSource;
|
||||
scaledSource.top = 0;
|
||||
@ -305,7 +353,7 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
||||
|
||||
int readStride = (expandedWidth * cacheBytes) /
|
||||
TexDecoder_GetBlockWidthInTexels(format);
|
||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource,
|
||||
EncodeToRamUsingShader(source_texture, scaledSource,
|
||||
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
|
||||
true, bScaleByHalf > 0 && !bFromZBuffer);
|
||||
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
|
||||
@ -315,10 +363,12 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false);
|
||||
|
||||
s_rgbToYuyvProgram.Bind();
|
||||
|
||||
EncodeToRamUsingShader(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
GL_REPORT_ERRORD();
|
||||
@ -326,7 +376,7 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des
|
||||
|
||||
|
||||
// Should be scale free.
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture)
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destRenderbuf)
|
||||
{
|
||||
u8* srcAddr = Memory::GetPointer(xfbAddr);
|
||||
if (!srcAddr)
|
||||
@ -342,51 +392,60 @@ 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);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, destRenderbuf);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
for (int i = 1; i < 8; ++i)
|
||||
TextureCache::DisableStage(i);
|
||||
|
||||
// activate source texture
|
||||
// set srcAddr as data for source texture
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture);
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE, s_srcTexture);
|
||||
|
||||
// TODO: make this less slow. (How?)
|
||||
if((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
|
||||
if ((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,0,0,s_srcTextureWidth, s_srcTextureHeight,
|
||||
glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0,0,0,s_srcTextureWidth, s_srcTextureHeight,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight,
|
||||
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight,
|
||||
0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
s_srcTextureWidth = (GLsizei)srcFmtWidth;
|
||||
s_srcTextureHeight = (GLsizei)srcHeight;
|
||||
}
|
||||
|
||||
glViewport(0, 0, srcWidth, srcHeight);
|
||||
|
||||
PixelShaderCache::SetCurrentShader(s_yuyvToRgbProgram.glprogid);
|
||||
s_yuyvToRgbProgram.Bind();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f((float)srcFmtWidth, (float)srcHeight); glVertex2f(1,-1);
|
||||
glTexCoord2f((float)srcFmtWidth, 0); glVertex2f(1,1);
|
||||
glTexCoord2f(0, 0); glVertex2f(-1,1);
|
||||
glTexCoord2f(0, (float)srcHeight); glVertex2f(-1,-1);
|
||||
glEnd();
|
||||
|
||||
if(s_cached_srcHeight != srcHeight || s_cached_srcWidth != srcWidth) {
|
||||
GLfloat vertices[] = {
|
||||
1.f, -1.f,
|
||||
(float)srcFmtWidth, (float)srcHeight,
|
||||
1.f, 1.f,
|
||||
(float)srcFmtWidth, 0.f,
|
||||
-1.f, 1.f,
|
||||
0.f, 0.f,
|
||||
-1.f, -1.f,
|
||||
0.f, (float)srcHeight
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*4*4, vertices, GL_STREAM_DRAW);
|
||||
|
||||
s_cached_srcHeight = srcHeight;
|
||||
s_cached_srcWidth = srcWidth;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// reset state
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
|
@ -35,7 +35,7 @@ void Shutdown();
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight);
|
||||
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destRenderbuf);
|
||||
|
||||
// returns size of the encoded data (in bytes)
|
||||
int EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
@ -29,10 +29,9 @@
|
||||
#include "ImageWrite.h"
|
||||
#include "BPMemory.h"
|
||||
#include "TextureCache.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "VertexManager.h"
|
||||
@ -40,6 +39,9 @@
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "PerfQueryBase.h"
|
||||
#include "Render.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
@ -48,62 +50,117 @@ extern NativeVertexFormat *g_nativeVertexFmt;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
//This are the initially requeted size for the buffers expresed in bytes
|
||||
const u32 MAX_IBUFFER_SIZE = 2*1024*1024;
|
||||
const u32 MAX_VBUFFER_SIZE = 16*1024*1024;
|
||||
|
||||
//static GLint max_Index_size = 0;
|
||||
|
||||
//static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0};
|
||||
//static int s_nCurVBOIndex = 0; // current free buffer
|
||||
static StreamBuffer *s_vertexBuffer;
|
||||
static StreamBuffer *s_indexBuffer;
|
||||
static u32 s_baseVertex;
|
||||
static u32 s_offset[3];
|
||||
|
||||
VertexManager::VertexManager()
|
||||
{
|
||||
// TODO: doesn't seem to be used anywhere
|
||||
CreateDeviceObjects();
|
||||
}
|
||||
|
||||
//glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*)&max_Index_size);
|
||||
//
|
||||
//if (max_Index_size > MAXIBUFFERSIZE)
|
||||
// max_Index_size = MAXIBUFFERSIZE;
|
||||
//
|
||||
//GL_REPORT_ERRORD();
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
GL_REPORT_ERRORD();
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
{
|
||||
s_vertexBuffer = new StreamBuffer(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE);
|
||||
m_vertex_buffers = s_vertexBuffer->getBuffer();
|
||||
s_indexBuffer = new StreamBuffer(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE, (StreamType)(DETECT_MASK & ~PINNED_MEMORY));
|
||||
m_index_buffers = s_indexBuffer->getBuffer();
|
||||
|
||||
|
||||
m_CurrentVertexFmt = NULL;
|
||||
m_last_vao = 0;
|
||||
}
|
||||
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
GL_REPORT_ERRORD();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0 );
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||
GL_REPORT_ERROR();
|
||||
|
||||
delete s_vertexBuffer;
|
||||
delete s_indexBuffer;
|
||||
GL_REPORT_ERROR();
|
||||
}
|
||||
|
||||
void VertexManager::Draw()
|
||||
void VertexManager::PrepareDrawBuffers(u32 stride)
|
||||
{
|
||||
if (IndexGenerator::GetNumTriangles() > 0)
|
||||
u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride;
|
||||
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
|
||||
u32 line_index_size = IndexGenerator::GetLineindexLen();
|
||||
u32 point_index_size = IndexGenerator::GetPointindexLen();
|
||||
u32 index_size = (triangle_index_size+line_index_size+point_index_size) * sizeof(u16);
|
||||
|
||||
s_vertexBuffer->Alloc(vertex_data_size, stride);
|
||||
u32 offset = s_vertexBuffer->Upload(GetVertexBuffer(), vertex_data_size);
|
||||
s_baseVertex = offset / stride;
|
||||
|
||||
s_indexBuffer->Alloc(index_size);
|
||||
if(triangle_index_size)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLES, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT, TIBuffer);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
s_offset[0] = s_indexBuffer->Upload((u8*)GetTriangleIndexBuffer(), triangle_index_size * sizeof(u16));
|
||||
}
|
||||
if (IndexGenerator::GetNumLines() > 0)
|
||||
if(line_index_size)
|
||||
{
|
||||
glDrawElements(GL_LINES, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT, LIBuffer);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
s_offset[1] = s_indexBuffer->Upload((u8*)GetLineIndexBuffer(), line_index_size * sizeof(u16));
|
||||
}
|
||||
if (IndexGenerator::GetNumPoints() > 0)
|
||||
if(point_index_size)
|
||||
{
|
||||
glDrawElements(GL_POINTS, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT, PIBuffer);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
s_offset[2] = s_indexBuffer->Upload((u8*)GetPointIndexBuffer(), point_index_size * sizeof(u16));
|
||||
}
|
||||
}
|
||||
|
||||
void VertexManager::Draw(u32 stride)
|
||||
{
|
||||
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
|
||||
u32 line_index_size = IndexGenerator::GetLineindexLen();
|
||||
u32 point_index_size = IndexGenerator::GetPointindexLen();
|
||||
if(g_ogl_config.bSupportsGLBaseVertex) {
|
||||
if (triangle_index_size > 0)
|
||||
{
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (line_index_size > 0)
|
||||
{
|
||||
glDrawElementsBaseVertex(GL_LINES, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (point_index_size > 0)
|
||||
{
|
||||
glDrawElementsBaseVertex(GL_POINTS, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
} else {
|
||||
if (triangle_index_size > 0)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLES, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (line_index_size > 0)
|
||||
{
|
||||
glDrawElements(GL_LINES, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (point_index_size > 0)
|
||||
{
|
||||
glDrawElements(GL_POINTS, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexManager::vFlush()
|
||||
{
|
||||
if (LocalVBuffer == s_pCurBufferPointer) return;
|
||||
if (Flushed) return;
|
||||
Flushed=true;
|
||||
VideoFifo_CheckEFBAccess();
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfregs.numTexGen.numTexGens,
|
||||
xfregs.numChan.numColorChans, xfregs.dualTexTrans.enabled, bpmem.ztex2.op,
|
||||
@ -134,13 +191,15 @@ void VertexManager::vFlush()
|
||||
|
||||
(void)GL_REPORT_ERROR();
|
||||
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, s_vboBuffers[s_nCurVBOIndex]);
|
||||
//glBufferData(GL_ARRAY_BUFFER, s_pCurBufferPointer - LocalVBuffer, LocalVBuffer, GL_STREAM_DRAW);
|
||||
GL_REPORT_ERRORD();
|
||||
GLVertexFormat *nativeVertexFmt = (GLVertexFormat*)g_nativeVertexFmt;
|
||||
u32 stride = nativeVertexFmt->GetVertexStride();
|
||||
|
||||
if(m_last_vao != nativeVertexFmt->VAO) {
|
||||
glBindVertexArray(nativeVertexFmt->VAO);
|
||||
m_last_vao = nativeVertexFmt->VAO;
|
||||
}
|
||||
|
||||
// setup the pointers
|
||||
if (g_nativeVertexFmt)
|
||||
g_nativeVertexFmt->SetupVertexPointers();
|
||||
PrepareDrawBuffers(stride);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
u32 usedtextures = 0;
|
||||
@ -153,19 +212,20 @@ void VertexManager::vFlush()
|
||||
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
|
||||
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (usedtextures & (1 << i))
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
TextureCache::SetNextStage(i);
|
||||
g_renderer->SetSamplerState(i % 4, i / 4);
|
||||
FourTexUnits &tex = bpmem.tex[i >> 2];
|
||||
TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i,
|
||||
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
|
||||
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
|
||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8),
|
||||
tex.texMode1[i&3].max_lod >> 4,
|
||||
(tex.texMode0[i&3].min_filter & 3),
|
||||
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
@ -178,59 +238,64 @@ void VertexManager::vFlush()
|
||||
}
|
||||
}
|
||||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
|
||||
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate
|
||||
&& bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||
|
||||
#ifdef USE_DUAL_SOURCE_BLEND
|
||||
bool dualSourcePossible = GLEW_ARB_blend_func_extended;
|
||||
// Makes sure we can actually do Dual source blending
|
||||
bool dualSourcePossible = g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
|
||||
|
||||
// finally bind
|
||||
FRAGMENTSHADER* ps;
|
||||
if (dualSourcePossible)
|
||||
{
|
||||
if (useDstAlpha)
|
||||
{
|
||||
// If host supports GL_ARB_blend_func_extended, we can do dst alpha in
|
||||
// the same pass as regular rendering.
|
||||
g_renderer->SetBlendMode(true);
|
||||
ps = PixelShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, g_nativeVertexFmt->m_components);
|
||||
ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, g_nativeVertexFmt->m_components);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_renderer->SetBlendMode(true);
|
||||
ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
}
|
||||
#else
|
||||
bool dualSourcePossible = false;
|
||||
FRAGMENTSHADER* ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
#endif
|
||||
VERTEXSHADER* vs = VertexShaderCache::SetShader(g_nativeVertexFmt->m_components);
|
||||
if (ps) PixelShaderCache::SetCurrentShader(ps->glprogid); // Lego Star Wars crashes here.
|
||||
if (vs) VertexShaderCache::SetCurrentShader(vs->glprogid);
|
||||
|
||||
Draw();
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
ProgramShaderCache::UploadConstants();
|
||||
|
||||
// setup the pointers
|
||||
if (g_nativeVertexFmt)
|
||||
g_nativeVertexFmt->SetupVertexPointers();
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
Draw(stride);
|
||||
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
//ERROR_LOG(VIDEO, "PerfQuery result: %d", g_perf_query->GetQueryResult(bpmem.zcontrol.early_ztest ? PQ_ZCOMP_OUTPUT_ZCOMPLOC : PQ_ZCOMP_OUTPUT));
|
||||
|
||||
// run through vertex groups again to set alpha
|
||||
if (useDstAlpha && !dualSourcePossible)
|
||||
{
|
||||
ps = PixelShaderCache::SetShader(DSTALPHA_ALPHA_PASS,g_nativeVertexFmt->m_components);
|
||||
if (ps) PixelShaderCache::SetCurrentShader(ps->glprogid);
|
||||
|
||||
ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS,g_nativeVertexFmt->m_components);
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
// Need to set these again, if we don't support UBO
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
}
|
||||
|
||||
// only update alpha
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
Draw();
|
||||
Draw(stride);
|
||||
|
||||
// restore color mask
|
||||
g_renderer->SetColorMask();
|
||||
|
||||
@ -238,22 +303,21 @@ void VertexManager::vFlush()
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
|
||||
|
||||
//s_nCurVBOIndex = (s_nCurVBOIndex + 1) % ARRAYSIZE(s_vboBuffers);
|
||||
s_pCurBufferPointer = LocalVBuffer;
|
||||
IndexGenerator::Start(TIBuffer,LIBuffer,PIBuffer);
|
||||
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
|
||||
{
|
||||
// save the shaders
|
||||
ProgramShaderCache::PCacheEntry prog = ProgramShaderCache::GetShaderProgram();
|
||||
char strfile[255];
|
||||
sprintf(strfile, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
|
||||
std::ofstream fps(strfile);
|
||||
fps << ps->strprog.c_str();
|
||||
std::ofstream fps;
|
||||
OpenFStream(fps, strfile, std::ios_base::out);
|
||||
fps << prog.shader.strpprog.c_str();
|
||||
sprintf(strfile, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
|
||||
std::ofstream fvs(strfile);
|
||||
fvs << vs->strprog.c_str();
|
||||
std::ofstream fvs;
|
||||
OpenFStream(fvs, strfile, std::ios_base::out);
|
||||
fvs << prog.shader.strvprog.c_str();
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.iLog & CONF_SAVETARGETS)
|
||||
|
@ -24,6 +24,19 @@
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class GLVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
PortableVertexDeclaration vtx_decl;
|
||||
|
||||
public:
|
||||
GLVertexFormat();
|
||||
~GLVertexFormat();
|
||||
|
||||
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
||||
virtual void SetupVertexPointers();
|
||||
|
||||
GLuint VAO;
|
||||
};
|
||||
|
||||
// Handles the OpenGL details of drawing lots of vertices quickly.
|
||||
// Other functionality is moving out.
|
||||
@ -31,14 +44,20 @@ class VertexManager : public ::VertexManager
|
||||
{
|
||||
public:
|
||||
VertexManager();
|
||||
|
||||
~VertexManager();
|
||||
NativeVertexFormat* CreateNativeVertexFormat();
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
// NativeVertexFormat use this
|
||||
GLuint m_vertex_buffers;
|
||||
GLuint m_index_buffers;
|
||||
GLuint m_last_vao;
|
||||
private:
|
||||
void Draw();
|
||||
// temp
|
||||
void Draw(u32 stride);
|
||||
void vFlush();
|
||||
void PrepareDrawBuffers(u32 stride);
|
||||
NativeVertexFormat *m_CurrentVertexFmt;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "Render.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "XFMemory.h"
|
||||
@ -37,235 +37,104 @@
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
GLuint VertexShaderCache::CurrentShader;
|
||||
bool VertexShaderCache::ShaderEnabled;
|
||||
|
||||
VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
|
||||
static int s_nMaxVertexInstructions;
|
||||
|
||||
|
||||
void VertexShaderCache::Init()
|
||||
void SetVSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
|
||||
{
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
CurrentShader = 0;
|
||||
last_entry = NULL;
|
||||
|
||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
|
||||
#if CG_VERSION_NUM == 2100
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
|
||||
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
s_nMaxVertexInstructions = 4096;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
vshaders.clear();
|
||||
}
|
||||
|
||||
|
||||
VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
|
||||
{
|
||||
// Possible optimization: Don't always generate the shader uid, but keep track of changes in BPStructs instead
|
||||
VertexShaderUid uid;
|
||||
GetVertexShaderUid(uid, components, API_OPENGL);
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
if (!strcmp(name, UniformNames[a]))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
if (tmp.shader.UniformLocations[a] == -1)
|
||||
return;
|
||||
else
|
||||
{
|
||||
glUniform4fv(tmp.shader.UniformLocations[a] + offset, count, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
VSCache::iterator iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
VSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry& entry = vshaders[uid];
|
||||
last_entry = &entry;
|
||||
VertexShaderCode code;
|
||||
GenerateVertexShaderCode(code, components, API_OPENGL);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
|
||||
SaveData(szTemp, code.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!code.GetBuffer() || !VertexShaderCache::CompileVertexShader(entry.shader, code.GetBuffer())) {
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram)
|
||||
{
|
||||
// Reset GL error before compiling shaders. Yeah, we need to investigate the causes of these.
|
||||
GLenum err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "glError %08x before VS!", err);
|
||||
}
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
char stropt[64];
|
||||
sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions);
|
||||
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
|
||||
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts);
|
||||
if (!cgIsProgram(tempprog)) {
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file(szTemp);
|
||||
file << pstrprogram;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile vertex 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 (%d):\n%s",
|
||||
szTemp,
|
||||
g_cgfProf,
|
||||
cgGetLastListing(g_cgcontext));
|
||||
|
||||
cgDestroyProgram(tempprog);
|
||||
ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
||||
ERROR_LOG(VIDEO, "%s", pstrprogram);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cgGetError() != CG_NO_ERROR)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
||||
WARN_LOG(VIDEO, "%s", pstrprogram);
|
||||
}
|
||||
|
||||
// This looks evil - we modify the program through the const char * we got from cgGetProgramString!
|
||||
// It SHOULD not have any nasty side effects though - but you never know...
|
||||
char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
|
||||
char *plocal = strstr(pcompiledprog, "program.local");
|
||||
while (plocal != NULL) {
|
||||
const char* penv = " program.env";
|
||||
memcpy(plocal, penv, 13);
|
||||
plocal = strstr(plocal + 13, "program.local");
|
||||
}
|
||||
glGenProgramsARB(1, &vs.glprogid);
|
||||
SetCurrentShader(vs.glprogid);
|
||||
|
||||
glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
|
||||
err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "%s", pstrprogram);
|
||||
ERROR_LOG(VIDEO, "%s", pcompiledprog);
|
||||
}
|
||||
|
||||
cgDestroyProgram(tempprog);
|
||||
#endif
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
vs.strprog = pstrprogram;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::DisableShader()
|
||||
{
|
||||
if (ShaderEnabled)
|
||||
{
|
||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VertexShaderCache::SetCurrentShader(GLuint Shader)
|
||||
{
|
||||
if (!ShaderEnabled)
|
||||
{
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled= true;
|
||||
}
|
||||
if (CurrentShader != Shader)
|
||||
{
|
||||
if(Shader != 0)
|
||||
CurrentShader = Shader;
|
||||
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, CurrentShader);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
|
||||
float const buf[4] = {f1, f2, f3, f4};
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if(GLEW_EXT_gpu_program_parameters)
|
||||
{
|
||||
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++,f+=4)
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f);
|
||||
}
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if(GLEW_EXT_gpu_program_parameters)
|
||||
float buf[4 * C_VENVCONST_END];
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
float buf[4 * C_VENVCONST_END];
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
buf[4*i ] = *f++;
|
||||
buf[4*i+1] = *f++;
|
||||
buf[4*i+2] = *f++;
|
||||
buf[4*i+3] = 0.f;
|
||||
}
|
||||
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
float buf[4];
|
||||
buf[0] = *f++;
|
||||
buf[1] = *f++;
|
||||
buf[2] = *f++;
|
||||
buf[3] = 0.f;
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, buf);
|
||||
}
|
||||
}
|
||||
buf[4*i ] = *f++;
|
||||
buf[4*i+1] = *f++;
|
||||
buf[4*i+2] = *f++;
|
||||
buf[4*i+3] = 0.f;
|
||||
}
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
@ -1,271 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include "Render.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "XFMemory.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
GLuint VertexShaderCache::CurrentShader;
|
||||
bool VertexShaderCache::ShaderEnabled;
|
||||
|
||||
VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
|
||||
static int s_nMaxVertexInstructions;
|
||||
|
||||
|
||||
void VertexShaderCache::Init()
|
||||
{
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled = true;
|
||||
CurrentShader = 0;
|
||||
last_entry = NULL;
|
||||
|
||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
|
||||
#if CG_VERSION_NUM == 2100
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
|
||||
{
|
||||
s_nMaxVertexInstructions = 4096;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
vshaders.clear();
|
||||
}
|
||||
|
||||
|
||||
VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
|
||||
{
|
||||
// Possible optimization: Don't always generate the shader uid, but keep track of changes in BPStructs instead
|
||||
VertexShaderUid uid;
|
||||
GetVertexShaderUid(uid, components, API_OPENGL);
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
VSCache::iterator iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
VSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry& entry = vshaders[uid];
|
||||
last_entry = &entry;
|
||||
ShaderCode code;
|
||||
GenerateShaderCode(code, components, API_OPENGL);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
|
||||
SaveData(szTemp, code.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!code.GetBuffer() || !VertexShaderCache::CompileVertexShader(entry.shader, code.GetBuffer())) {
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram)
|
||||
{
|
||||
// Reset GL error before compiling shaders. Yeah, we need to investigate the causes of these.
|
||||
GLenum err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "glError %08x before VS!", err);
|
||||
}
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
char stropt[64];
|
||||
sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions);
|
||||
const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
|
||||
CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts);
|
||||
if (!cgIsProgram(tempprog)) {
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file(szTemp);
|
||||
file << pstrprogram;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile vertex 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 (%d):\n%s",
|
||||
szTemp,
|
||||
g_cgfProf,
|
||||
cgGetLastListing(g_cgcontext));
|
||||
|
||||
cgDestroyProgram(tempprog);
|
||||
ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
||||
ERROR_LOG(VIDEO, "%s", pstrprogram);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cgGetError() != CG_NO_ERROR)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
||||
WARN_LOG(VIDEO, "%s", pstrprogram);
|
||||
}
|
||||
|
||||
// This looks evil - we modify the program through the const char * we got from cgGetProgramString!
|
||||
// It SHOULD not have any nasty side effects though - but you never know...
|
||||
char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
|
||||
char *plocal = strstr(pcompiledprog, "program.local");
|
||||
while (plocal != NULL) {
|
||||
const char* penv = " program.env";
|
||||
memcpy(plocal, penv, 13);
|
||||
plocal = strstr(plocal + 13, "program.local");
|
||||
}
|
||||
glGenProgramsARB(1, &vs.glprogid);
|
||||
SetCurrentShader(vs.glprogid);
|
||||
|
||||
glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);
|
||||
err = GL_REPORT_ERROR();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "%s", pstrprogram);
|
||||
ERROR_LOG(VIDEO, "%s", pcompiledprog);
|
||||
}
|
||||
|
||||
cgDestroyProgram(tempprog);
|
||||
#endif
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
vs.strprog = pstrprogram;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VertexShaderCache::DisableShader()
|
||||
{
|
||||
if (ShaderEnabled)
|
||||
{
|
||||
glDisable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VertexShaderCache::SetCurrentShader(GLuint Shader)
|
||||
{
|
||||
if (!ShaderEnabled)
|
||||
{
|
||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
||||
ShaderEnabled= true;
|
||||
}
|
||||
if (CurrentShader != Shader)
|
||||
{
|
||||
if(Shader != 0)
|
||||
CurrentShader = Shader;
|
||||
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, CurrentShader);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if(GLEW_EXT_gpu_program_parameters)
|
||||
{
|
||||
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++,f+=4)
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if(GLEW_EXT_gpu_program_parameters)
|
||||
{
|
||||
float buf[4 * C_VENVCONST_END];
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
buf[4*i ] = *f++;
|
||||
buf[4*i+1] = *f++;
|
||||
buf[4*i+2] = *f++;
|
||||
buf[4*i+3] = 0.f;
|
||||
}
|
||||
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
float buf[4];
|
||||
buf[0] = *f++;
|
||||
buf[1] = *f++;
|
||||
buf[2] = *f++;
|
||||
buf[3] = 0.f;
|
||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGL
|
@ -1,76 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _VERTEXSHADERCACHE_H_
|
||||
#define _VERTEXSHADERCACHE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "BPMemory.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
struct VERTEXSHADER
|
||||
{
|
||||
VERTEXSHADER() : glprogid(0) {}
|
||||
GLuint glprogid; // opengl program id
|
||||
|
||||
std::string strprog;
|
||||
};
|
||||
|
||||
class VertexShaderCache
|
||||
{
|
||||
struct VSCacheEntry
|
||||
{
|
||||
VERTEXSHADER shader;
|
||||
VertexShaderUid safe_uid;
|
||||
VSCacheEntry() {}
|
||||
void Destroy() {
|
||||
// printf("Destroying vs %i\n", shader.glprogid);
|
||||
glDeleteProgramsARB(1, &shader.glprogid);
|
||||
shader.glprogid = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
||||
|
||||
static VSCache vshaders;
|
||||
|
||||
static VSCacheEntry* last_entry;
|
||||
static VertexShaderUid last_uid; // TODO: Use reference instead..
|
||||
|
||||
static GLuint CurrentShader;
|
||||
static bool ShaderEnabled;
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static VERTEXSHADER* SetShader(u32 components);
|
||||
static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
|
||||
|
||||
static void SetCurrentShader(GLuint Shader);
|
||||
static void DisableShader();
|
||||
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
||||
#endif // _VERTEXSHADERCACHE_H_
|
@ -1,76 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// 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, version 2.0.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _VERTEXSHADERCACHE_H_
|
||||
#define _VERTEXSHADERCACHE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "BPMemory.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
struct VERTEXSHADER
|
||||
{
|
||||
VERTEXSHADER() : glprogid(0) {}
|
||||
GLuint glprogid; // opengl program id
|
||||
|
||||
std::string strprog;
|
||||
};
|
||||
|
||||
class VertexShaderCache
|
||||
{
|
||||
struct VSCacheEntry
|
||||
{
|
||||
VERTEXSHADER shader;
|
||||
VertexShaderUid safe_uid;
|
||||
VSCacheEntry() {}
|
||||
void Destroy() {
|
||||
// printf("Destroying vs %i\n", shader.glprogid);
|
||||
glDeleteProgramsARB(1, &shader.glprogid);
|
||||
shader.glprogid = 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<ShaderUid, VSCacheEntry> VSCache;
|
||||
|
||||
static VSCache vshaders;
|
||||
|
||||
static VSCacheEntry* last_entry;
|
||||
static ShaderUid last_uid; // TODO: Use reference instead..
|
||||
|
||||
static GLuint CurrentShader;
|
||||
static bool ShaderEnabled;
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static VERTEXSHADER* SetShader(u32 components);
|
||||
static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
|
||||
|
||||
static void SetCurrentShader(GLuint Shader);
|
||||
static void DisableShader();
|
||||
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
||||
#endif // _VERTEXSHADERCACHE_H_
|
@ -15,6 +15,7 @@ class VideoBackend : public VideoBackendHardware
|
||||
std::string GetName();
|
||||
|
||||
void Video_Prepare();
|
||||
void Video_Cleanup();
|
||||
|
||||
void ShowConfig(void* parent);
|
||||
|
||||
|
@ -55,6 +55,7 @@ Make AA apply instantly during gameplay if possible
|
||||
#include "LogManager.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "EmuWindow.h"
|
||||
@ -79,10 +80,9 @@ Make AA apply instantly during gameplay if possible
|
||||
#include "VertexLoader.h"
|
||||
#include "VertexLoaderManager.h"
|
||||
#include "VertexManager.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "CommandProcessor.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "TextureConverter.h"
|
||||
@ -92,6 +92,8 @@ Make AA apply instantly during gameplay if possible
|
||||
#include "FramebufferManager.h"
|
||||
#include "Core.h"
|
||||
#include "Host.h"
|
||||
#include "SamplerCache.h"
|
||||
#include "PerfQuery.h"
|
||||
|
||||
#include "VideoState.h"
|
||||
#include "VideoBackend.h"
|
||||
@ -107,36 +109,39 @@ std::string VideoBackend::GetName()
|
||||
|
||||
void GetShaders(std::vector<std::string> &shaders)
|
||||
{
|
||||
shaders.clear();
|
||||
if (File::IsDirectory(File::GetUserPath(D_SHADERS_IDX)))
|
||||
{
|
||||
File::FSTEntry entry;
|
||||
File::ScanDirectoryTree(File::GetUserPath(D_SHADERS_IDX), entry);
|
||||
for (u32 i = 0; i < entry.children.size(); i++)
|
||||
{
|
||||
std::string name = entry.children[i].virtualName.c_str();
|
||||
if (!strcasecmp(name.substr(name.size() - 4).c_str(), ".txt"))
|
||||
name = name.substr(0, name.size() - 4);
|
||||
shaders.push_back(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File::CreateDir(File::GetUserPath(D_SHADERS_IDX).c_str());
|
||||
}
|
||||
shaders.clear();
|
||||
if (File::IsDirectory(File::GetUserPath(D_SHADERS_IDX)))
|
||||
{
|
||||
File::FSTEntry entry;
|
||||
File::ScanDirectoryTree(File::GetUserPath(D_SHADERS_IDX), entry);
|
||||
for (u32 i = 0; i < entry.children.size(); i++)
|
||||
{
|
||||
std::string name = entry.children[i].virtualName.c_str();
|
||||
if (!strcasecmp(name.substr(name.size() - 4).c_str(), ".txt")) {
|
||||
name = name.substr(0, name.size() - 4);
|
||||
shaders.push_back(name);
|
||||
}
|
||||
}
|
||||
std::sort(shaders.begin(), shaders.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
File::CreateDir(File::GetUserPath(D_SHADERS_IDX).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void InitBackendInfo()
|
||||
{
|
||||
g_Config.backend_info.APIType = API_OPENGL;
|
||||
g_Config.backend_info.bUseRGBATextures = false;
|
||||
g_Config.backend_info.bUseRGBATextures = true;
|
||||
g_Config.backend_info.bUseMinimalMipCount = false;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = false; // supported, but broken
|
||||
//g_Config.backend_info.bSupportsDualSourceBlend = true; // is gpu depenend and must be set in renderer
|
||||
g_Config.backend_info.bSupportsFormatReinterpretation = false;
|
||||
g_Config.backend_info.bSupportsPixelLighting = true;
|
||||
|
||||
// aamodes
|
||||
const char* caamodes[] = {"None", "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA"};
|
||||
const char* caamodes[] = {"None", "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"};
|
||||
g_Config.backend_info.AAModes.assign(caamodes, caamodes + sizeof(caamodes)/sizeof(*caamodes));
|
||||
|
||||
// pp shaders
|
||||
@ -189,21 +194,24 @@ void VideoBackend::Video_Prepare()
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
|
||||
g_texture_cache = new TextureCache;
|
||||
|
||||
BPInit();
|
||||
g_vertex_manager = new VertexManager;
|
||||
g_perf_query = new PerfQuery;
|
||||
Fifo_Init(); // must be done before OpcodeDecoder_Init()
|
||||
OpcodeDecoder_Init();
|
||||
VertexShaderCache::Init();
|
||||
VertexShaderManager::Init();
|
||||
PixelShaderCache::Init();
|
||||
PixelShaderManager::Init();
|
||||
ProgramShaderCache::Init();
|
||||
PostProcessing::Init();
|
||||
g_texture_cache = new TextureCache();
|
||||
g_sampler_cache = new SamplerCache();
|
||||
Renderer::Init();
|
||||
GL_REPORT_ERRORD();
|
||||
VertexLoaderManager::Init();
|
||||
TextureConverter::Init();
|
||||
#ifndef _M_GENERIC
|
||||
DLCache::Init();
|
||||
#endif
|
||||
|
||||
// Notify the core that the video backend is ready
|
||||
Host_Message(WM_USER_CREATE);
|
||||
@ -212,32 +220,40 @@ void VideoBackend::Video_Prepare()
|
||||
void VideoBackend::Shutdown()
|
||||
{
|
||||
s_BackendInitialized = false;
|
||||
GLInterface->Shutdown();
|
||||
}
|
||||
|
||||
void VideoBackend::Video_Cleanup() {
|
||||
|
||||
if (g_renderer)
|
||||
{
|
||||
s_efbAccessRequested = false;
|
||||
s_FifoShuttingDown = false;
|
||||
s_swapRequested = false;
|
||||
#ifndef _M_GENERIC
|
||||
DLCache::Shutdown();
|
||||
#endif
|
||||
Fifo_Shutdown();
|
||||
PostProcessing::Shutdown();
|
||||
|
||||
// The following calls are NOT Thread Safe
|
||||
// And need to be called from the video thread
|
||||
Renderer::Shutdown();
|
||||
TextureConverter::Shutdown();
|
||||
VertexLoaderManager::Shutdown();
|
||||
VertexShaderCache::Shutdown();
|
||||
delete g_sampler_cache;
|
||||
g_sampler_cache = NULL;
|
||||
delete g_texture_cache;
|
||||
g_texture_cache = NULL;
|
||||
PostProcessing::Shutdown();
|
||||
ProgramShaderCache::Shutdown();
|
||||
VertexShaderManager::Shutdown();
|
||||
PixelShaderManager::Shutdown();
|
||||
PixelShaderCache::Shutdown();
|
||||
delete g_vertex_manager;
|
||||
delete g_texture_cache;
|
||||
g_vertex_manager = NULL;
|
||||
OpcodeDecoder_Shutdown();
|
||||
delete g_renderer;
|
||||
g_renderer = NULL;
|
||||
g_texture_cache = NULL;
|
||||
}
|
||||
GLInterface->Shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user