Silently remove Plugin_VideoMerge again...
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6404 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
8b9b66911f
commit
6fe343df61
|
@ -251,15 +251,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLRun", "..\Externals\CLRun
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SVNRevGen", "Core\Common\SVNRevGen.vcproj", "{B807E8DB-4241-4754-BC2A-2F435BCA881A}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SVNRevGen", "Core\Common\SVNRevGen.vcproj", "{B807E8DB-4241-4754-BC2A-2F435BCA881A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Plugin_VideoMerge", "Plugins\Plugin_VideoMerge\Plugin_VideoMerge.vcproj", "{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{11F55366-12EC-4C44-A8CB-1D4E315D61ED} = {11F55366-12EC-4C44-A8CB-1D4E315D61ED}
|
|
||||||
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA} = {E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}
|
|
||||||
{1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE} = {1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE}
|
|
||||||
{B807E8DB-4241-4754-BC2A-2F435BCA881A} = {B807E8DB-4241-4754-BC2A-2F435BCA881A}
|
|
||||||
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wiiuse", "Core\wiiuse\wiiuse.vcproj", "{52F70249-373A-4401-A70A-FF22760EC1B8}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wiiuse", "Core\wiiuse\wiiuse.vcproj", "{52F70249-373A-4401-A70A-FF22760EC1B8}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
|
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
|
||||||
|
@ -647,12 +638,6 @@ Global
|
||||||
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|Win32.Build.0 = Release|Win32
|
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|Win32.Build.0 = Release|Win32
|
||||||
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|x64.ActiveCfg = Release|Win32
|
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|x64.ActiveCfg = Release|Win32
|
||||||
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|x64.Build.0 = Release|Win32
|
{B807E8DB-4241-4754-BC2A-2F435BCA881A}.Release|x64.Build.0 = Release|Win32
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.DebugFast|Win32.ActiveCfg = Debug|x64
|
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.DebugFast|x64.ActiveCfg = Debug|x64
|
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|Win32.ActiveCfg = Debug|Win32
|
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|Win32.Build.0 = Debug|Win32
|
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|x64.ActiveCfg = Debug|x64
|
{52F70249-373A-4401-A70A-FF22760EC1B8}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
|
|
@ -1,808 +0,0 @@
|
||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="9.00"
|
|
||||||
Name="Plugin_VideoMerge"
|
|
||||||
ProjectGUID="{CA7F67A1-7DD9-4C49-94B8-F62AF3D4C72E}"
|
|
||||||
RootNamespace="Plugin_VideoMerge"
|
|
||||||
Keyword="Win32Proj"
|
|
||||||
TargetFrameworkVersion="196613"
|
|
||||||
>
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"
|
|
||||||
/>
|
|
||||||
<Platform
|
|
||||||
Name="x64"
|
|
||||||
/>
|
|
||||||
</Platforms>
|
|
||||||
<ToolFiles>
|
|
||||||
</ToolFiles>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="1"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;../../Core/VideoCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew\include;..\..\..\Externals\CLRun\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
|
||||||
MinimalRebuild="false"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="1"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderThrough="stdafx.h"
|
|
||||||
PrecompiledHeaderFile="$(IntDir)/VideoMerge.pch"
|
|
||||||
AssemblerListingLocation="$(IntDir)\"
|
|
||||||
ProgramDataBaseFileName="$(IntDir)\"
|
|
||||||
WarningLevel="3"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
ForcedIncludeFiles="stdafx.h"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
IgnoreImportLibrary="false"
|
|
||||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib cg.lib cgGL.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib"
|
|
||||||
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoMergeD.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
|
||||||
IgnoreDefaultLibraryNames=""
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
|
||||||
SubSystem="0"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|x64"
|
|
||||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="1"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;../../Core/VideoCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew\include;..\..\..\Externals\CLRun\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
|
||||||
MinimalRebuild="false"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="1"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderThrough="stdafx.h"
|
|
||||||
PrecompiledHeaderFile="$(IntDir)/VideoMerge.pch"
|
|
||||||
AssemblerListingLocation="$(IntDir)\"
|
|
||||||
ProgramDataBaseFileName="$(IntDir)\"
|
|
||||||
WarningLevel="3"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
ForcedIncludeFiles="stdafx.h"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
IgnoreImportLibrary="false"
|
|
||||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib cg.lib cgGL.lib opengl32.lib glew64s.lib glu32.lib rpcrt4.lib"
|
|
||||||
OutputFile="..\..\..\Binary\x64\Plugins\Plugin_VideoMergeD.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg64;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
IgnoreDefaultLibraryNames=""
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
|
||||||
SubSystem="0"
|
|
||||||
RandomizedBaseAddress="1"
|
|
||||||
DataExecutionPrevention="0"
|
|
||||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="1"
|
|
||||||
WholeProgramOptimization="1"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
EnableIntrinsicFunctions="true"
|
|
||||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;../../Core/VideoCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew\include;..\..\..\Externals\CLRun\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;_WIN32;PLUGIN_VIDEOSOFTWARE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
|
||||||
RuntimeLibrary="0"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderThrough="stdafx.h"
|
|
||||||
PrecompiledHeaderFile="$(IntDir)/VideoMerge.pch"
|
|
||||||
WarningLevel="3"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
ForcedIncludeFiles="stdafx.h"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
IgnoreImportLibrary="false"
|
|
||||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib cg.lib cgGL.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib libjpeg.lib"
|
|
||||||
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoMerge.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
IgnoreDefaultLibraryNames=""
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
|
||||||
TargetMachine="1"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|x64"
|
|
||||||
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
|
||||||
ConfigurationType="2"
|
|
||||||
CharacterSet="1"
|
|
||||||
WholeProgramOptimization="1"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TargetEnvironment="3"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
AdditionalOptions="/MP"
|
|
||||||
Optimization="2"
|
|
||||||
EnableIntrinsicFunctions="true"
|
|
||||||
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;../../Core/VideoCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew\include;..\..\..\Externals\CLRun\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;_WIN32;PLUGIN_VIDEOSOFTWARE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
|
|
||||||
RuntimeLibrary="0"
|
|
||||||
EnableFunctionLevelLinking="true"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
PrecompiledHeaderThrough="stdafx.h"
|
|
||||||
PrecompiledHeaderFile="$(IntDir)/VideoMerge.pch"
|
|
||||||
WarningLevel="3"
|
|
||||||
DebugInformationFormat="3"
|
|
||||||
ForcedIncludeFiles="stdafx.h"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
IgnoreImportLibrary="false"
|
|
||||||
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib cg.lib cgGL.lib opengl32.lib glew64s.lib glu32.lib rpcrt4.lib libjpeg64.lib"
|
|
||||||
OutputFile="..\..\..\Binary\x64\Plugins\Plugin_VideoMerge.dll"
|
|
||||||
LinkIncremental="1"
|
|
||||||
AdditionalLibraryDirectories=""..\..\core\common\$(PlatformName)\$(ConfigurationName)";..\..\..\Externals\Cg64;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;"..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)""
|
|
||||||
IgnoreAllDefaultLibraries="false"
|
|
||||||
IgnoreDefaultLibraryNames=""
|
|
||||||
GenerateDebugInformation="true"
|
|
||||||
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
|
|
||||||
SubSystem="2"
|
|
||||||
OptimizeReferences="2"
|
|
||||||
EnableCOMDATFolding="2"
|
|
||||||
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
|
|
||||||
TargetMachine="17"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCALinkTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManifestTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXDCMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCBscMakeTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCFxCopTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAppVerifierTool"
|
|
||||||
/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Render"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\BPFunctions.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\FramebufferManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\FramebufferManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\PixelShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\PixelShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\Renderer.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\Renderer.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\TextureCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\TextureCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VertexManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VertexManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VertexShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VertexShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="OGL"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_RasterFont.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_RasterFont.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<Filter
|
|
||||||
Name="GL"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_GLUtil.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_GLUtil.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_GLWindow.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_TextureConverter.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_TextureConverter.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Render"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_FramebufferManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_FramebufferManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_PixelShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_PixelShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_PostProcessing.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_PostProcessing.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_Render.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_Render.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_VertexShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_VertexShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_XFB.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_XFB.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Decoder"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_NativeVertexFormat.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_TextureCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_TextureCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_VertexManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\OGL\OGL_VertexManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="DX11"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_GfxState.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_GfxState.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<Filter
|
|
||||||
Name="D3D"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DBase.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DBase.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DBlob.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DBlob.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DShader.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DShader.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DTexture.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DTexture.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DUtil.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_D3DUtil.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Render"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_FramebufferManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_FramebufferManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_PixelShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_PixelShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_Render.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_Render.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_VertexShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_VertexShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Decoder"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_NativeVertexFormat.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_TextureCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_TextureCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_VertexManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX11\DX11_VertexManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="DX9"
|
|
||||||
>
|
|
||||||
<Filter
|
|
||||||
Name="D3D"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DBase.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DBase.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DShader.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DShader.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DTexture.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DTexture.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DUtil.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_D3DUtil.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Render"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_FramebufferManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_FramebufferManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_PixelShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_PixelShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_Render.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_Render.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_VertexShaderCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_VertexShaderCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Decoder"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_NativeVertexFormat.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_TextureCache.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_TextureCache.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_TextureConverter.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_TextureConverter.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_VertexManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\DX9\DX9_VertexManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="ConfigDiag"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VideoConfigDiag.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\VideoConfigDiag.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\EmuWindow.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\EmuWindow.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\Main.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\Main.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\PluginSpecs\pluginspecs_video.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
|
@ -1,144 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "BPFunctions.h"
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VertexManager.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
namespace BPFunctions
|
|
||||||
{
|
|
||||||
|
|
||||||
void FlushPipeline()
|
|
||||||
{
|
|
||||||
g_vertex_manager->Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetGenerationMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetGenerationMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetScissor(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetScissorRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLineWidth(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetLineWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetDepthMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetDepthMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetBlendMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetBlendMode(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetDitherMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetDitherMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLogicOpMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetLogicOpMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetColorMask(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetColorMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const int &scaleByHalf)
|
|
||||||
{
|
|
||||||
if (!g_ActiveConfig.bEFBCopyDisable)
|
|
||||||
{
|
|
||||||
// if (g_ActiveConfig.bCopyEFBToTexture)
|
|
||||||
// {
|
|
||||||
g_texture_cache->CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, !!scaleByHalf, rc);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// PanicAlert("TODO: Implement EFB copying to RAM %s %d\n", __FILE__, __LINE__);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearScreen(const BPCmd &bp, const EFBRectangle &rc)
|
|
||||||
{
|
|
||||||
bool colorEnable = bpmem.blendmode.colorupdate;
|
|
||||||
bool alphaEnable = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24 && bpmem.blendmode.alphaupdate);
|
|
||||||
bool zEnable = bpmem.zmode.updateenable;
|
|
||||||
|
|
||||||
if (colorEnable || alphaEnable || zEnable)
|
|
||||||
{
|
|
||||||
u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
|
|
||||||
u32 z = bpmem.clearZValue;
|
|
||||||
|
|
||||||
g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestoreRenderState(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetConfig(const int &type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case CONFIG_ISWII:
|
|
||||||
return g_VideoInitialize.bWii;
|
|
||||||
case CONFIG_DISABLEFOG:
|
|
||||||
return g_ActiveConfig.bDisableFog;
|
|
||||||
case CONFIG_SHOWEFBREGIONS:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
PanicAlert("GetConfig Error: Unknown Config Type!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *GetPointer(const u32 &address)
|
|
||||||
{
|
|
||||||
return g_VideoInitialize.pGetMemoryPointer(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTextureMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
g_renderer->SetSamplerState(bp.address & 3, (bp.address & 0xE0) == 0xA0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetInterlacingMode(const BPCmd &bp)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,338 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "StringUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
|
|
||||||
#include <D3Dcompiler.h>
|
|
||||||
|
|
||||||
#pragma comment(lib, "dxguid.lib")
|
|
||||||
#pragma comment(lib, "d3d11.lib")
|
|
||||||
#pragma comment(lib, "dxgi.lib")
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
HINSTANCE hD3DXDll = NULL;
|
|
||||||
D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL;
|
|
||||||
D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL;
|
|
||||||
D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL;
|
|
||||||
D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL;
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
ID3D11Device* device = NULL;
|
|
||||||
ID3D11DeviceContext* context = NULL;
|
|
||||||
IDXGISwapChain* swapchain = NULL;
|
|
||||||
D3D_FEATURE_LEVEL featlevel;
|
|
||||||
D3DTexture2D* backbuf = NULL;
|
|
||||||
HWND hWnd;
|
|
||||||
|
|
||||||
bool bgra_textures_supported;
|
|
||||||
|
|
||||||
#define NUM_SUPPORTED_FEATURE_LEVELS 3
|
|
||||||
const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = {
|
|
||||||
D3D_FEATURE_LEVEL_11_0,
|
|
||||||
D3D_FEATURE_LEVEL_10_1,
|
|
||||||
D3D_FEATURE_LEVEL_10_0
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned int xres, yres;
|
|
||||||
|
|
||||||
bool bFrameInProgress = false;
|
|
||||||
|
|
||||||
HRESULT Create(HWND wnd)
|
|
||||||
{
|
|
||||||
hWnd = wnd;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
RECT client;
|
|
||||||
GetClientRect(hWnd, &client);
|
|
||||||
xres = client.right - client.left;
|
|
||||||
yres = client.bottom - client.top;
|
|
||||||
|
|
||||||
// try to load D3DX11 first to check whether we have proper runtime support
|
|
||||||
// try to use the dll the plugin was compiled against first - don't bother about debug runtimes
|
|
||||||
hD3DXDll = LoadLibraryA(StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str());
|
|
||||||
if (!hD3DXDll)
|
|
||||||
{
|
|
||||||
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
|
|
||||||
hD3DXDll = LoadLibraryA("d3dx11_42.dll");
|
|
||||||
if (!hD3DXDll)
|
|
||||||
{
|
|
||||||
MessageBoxA(NULL, "Failed to load d3dx11_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NOTICE_LOG(VIDEO, "Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
PD3DX11CompileFromMemory = (D3DX11COMPILEFROMMEMORYTYPE)GetProcAddress(hD3DXDll, "D3DX11CompileFromMemory");
|
|
||||||
if (PD3DX11CompileFromMemory == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11CompileFromMemory!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
PD3DX11FilterTexture = (D3DX11FILTERTEXTURETYPE)GetProcAddress(hD3DXDll, "D3DX11FilterTexture");
|
|
||||||
if (PD3DX11FilterTexture == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11FilterTexture!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
PD3DX11SaveTextureToFileA = (D3DX11SAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileA");
|
|
||||||
if (PD3DX11SaveTextureToFileA == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
PD3DX11SaveTextureToFileW = (D3DX11SAVETEXTURETOFILEWTYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileW");
|
|
||||||
if (PD3DX11SaveTextureToFileW == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileW!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
// D3DX11 is fine, initialize D3D11
|
|
||||||
IDXGIFactory* factory;
|
|
||||||
IDXGIAdapter* adapter;
|
|
||||||
IDXGIOutput* output;
|
|
||||||
hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
|
|
||||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
// try using the first one
|
|
||||||
hr = factory->EnumAdapters(0, &adapter);
|
|
||||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this configurable
|
|
||||||
hr = adapter->EnumOutputs(0, &output);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
// try using the first one
|
|
||||||
hr = adapter->EnumOutputs(0, &output);
|
|
||||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate outputs"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this will need to be changed once multisampling gets implemented
|
|
||||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
|
|
||||||
memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
|
|
||||||
swap_chain_desc.BufferCount = 1;
|
|
||||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
||||||
swap_chain_desc.OutputWindow = wnd;
|
|
||||||
swap_chain_desc.SampleDesc.Count = 1;
|
|
||||||
swap_chain_desc.SampleDesc.Quality = 0;
|
|
||||||
swap_chain_desc.Windowed = TRUE;
|
|
||||||
|
|
||||||
DXGI_MODE_DESC mode_desc;
|
|
||||||
memset(&mode_desc, 0, sizeof(mode_desc));
|
|
||||||
mode_desc.Width = xres;
|
|
||||||
mode_desc.Height = yres;
|
|
||||||
mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
|
||||||
hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, NULL);
|
|
||||||
if (FAILED(hr))
|
|
||||||
MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
|
|
||||||
// forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported!
|
|
||||||
swap_chain_desc.BufferDesc.Width = xres;
|
|
||||||
swap_chain_desc.BufferDesc.Height = yres;
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
D3D11_CREATE_DEVICE_FLAG device_flags = (D3D11_CREATE_DEVICE_FLAG)(D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_SINGLETHREADED);
|
|
||||||
#else
|
|
||||||
D3D11_CREATE_DEVICE_FLAG device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
|
|
||||||
#endif
|
|
||||||
hr = D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, device_flags,
|
|
||||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
|
|
||||||
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
|
|
||||||
&featlevel, &context);
|
|
||||||
if (FAILED(hr) || !device || !context || !swapchain)
|
|
||||||
{
|
|
||||||
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
SAFE_RELEASE(device);
|
|
||||||
SAFE_RELEASE(context);
|
|
||||||
SAFE_RELEASE(swapchain);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
|
|
||||||
SAFE_RELEASE(factory);
|
|
||||||
SAFE_RELEASE(output);
|
|
||||||
SAFE_RELEASE(adapter);
|
|
||||||
|
|
||||||
ID3D11Texture2D* buf;
|
|
||||||
hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
SAFE_RELEASE(device);
|
|
||||||
SAFE_RELEASE(context);
|
|
||||||
SAFE_RELEASE(swapchain);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
|
||||||
SAFE_RELEASE(buf);
|
|
||||||
CHECK(backbuf!=NULL, "Create back buffer texture");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
|
|
||||||
|
|
||||||
context->OMSetRenderTargets(1, &backbuf->GetRTV(), NULL);
|
|
||||||
|
|
||||||
// BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware
|
|
||||||
UINT format_support;
|
|
||||||
device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support);
|
|
||||||
bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
|
|
||||||
|
|
||||||
gfxstate = new EmuGfxState;
|
|
||||||
stateman = new StateManager;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close()
|
|
||||||
{
|
|
||||||
// unload D3DX11
|
|
||||||
FreeLibrary(hD3DXDll);
|
|
||||||
PD3DX11FilterTexture = NULL;
|
|
||||||
PD3DX11SaveTextureToFileA = NULL;
|
|
||||||
PD3DX11SaveTextureToFileW = NULL;
|
|
||||||
|
|
||||||
// release all bound resources
|
|
||||||
context->ClearState();
|
|
||||||
SAFE_RELEASE(backbuf);
|
|
||||||
SAFE_RELEASE(swapchain);
|
|
||||||
SAFE_DELETE(gfxstate);
|
|
||||||
SAFE_DELETE(stateman);
|
|
||||||
context->Flush(); // immediately destroy device objects
|
|
||||||
|
|
||||||
SAFE_RELEASE(context);
|
|
||||||
ULONG references = device->Release();
|
|
||||||
if (references)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NOTICE_LOG(VIDEO, "Successfully released all device references!");
|
|
||||||
}
|
|
||||||
device = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* just returning the 4_0 ones here */
|
|
||||||
const char* VertexShaderVersionString() { return "vs_4_0"; }
|
|
||||||
const char* PixelShaderVersionString() { return "ps_4_0"; }
|
|
||||||
|
|
||||||
D3DTexture2D* &GetBackBuffer() { return backbuf; }
|
|
||||||
unsigned int GetBackBufferWidth() { return xres; }
|
|
||||||
unsigned int GetBackBufferHeight() { return yres; }
|
|
||||||
|
|
||||||
bool BGRATexturesSupported() { return bgra_textures_supported; }
|
|
||||||
|
|
||||||
// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11
|
|
||||||
unsigned int GetMaxTextureSize()
|
|
||||||
{
|
|
||||||
switch (featlevel)
|
|
||||||
{
|
|
||||||
case D3D_FEATURE_LEVEL_11_0:
|
|
||||||
return 16384;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_1:
|
|
||||||
case D3D_FEATURE_LEVEL_10_0:
|
|
||||||
return 8192;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_3:
|
|
||||||
return 4096;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_9_2:
|
|
||||||
case D3D_FEATURE_LEVEL_9_1:
|
|
||||||
return 2048;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset()
|
|
||||||
{
|
|
||||||
// release all back buffer references
|
|
||||||
SAFE_RELEASE(backbuf);
|
|
||||||
|
|
||||||
// resize swapchain buffers
|
|
||||||
RECT client;
|
|
||||||
GetClientRect(hWnd, &client);
|
|
||||||
xres = client.right - client.left;
|
|
||||||
yres = client.bottom - client.top;
|
|
||||||
D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
|
|
||||||
|
|
||||||
// recreate back buffer texture
|
|
||||||
ID3D11Texture2D* buf;
|
|
||||||
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
SAFE_RELEASE(device);
|
|
||||||
SAFE_RELEASE(context);
|
|
||||||
SAFE_RELEASE(swapchain);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
|
||||||
SAFE_RELEASE(buf);
|
|
||||||
CHECK(backbuf!=NULL, "Create back buffer texture");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BeginFrame()
|
|
||||||
{
|
|
||||||
if (bFrameInProgress)
|
|
||||||
{
|
|
||||||
PanicAlert("BeginFrame called although a frame is already in progress");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bFrameInProgress = true;
|
|
||||||
return (device != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndFrame()
|
|
||||||
{
|
|
||||||
if (!bFrameInProgress)
|
|
||||||
{
|
|
||||||
PanicAlert("EndFrame called although no frame is in progress");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bFrameInProgress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Present()
|
|
||||||
{
|
|
||||||
// TODO: Is 1 the correct value for vsyncing?
|
|
||||||
swapchain->Present((UINT)g_ActiveConfig.bVSync, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,96 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include <d3dx11.h>
|
|
||||||
#include "DX11_GfxState.h"
|
|
||||||
#include "DX11_D3DBlob.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; }
|
|
||||||
#define SAFE_DELETE(x) { delete (x); (x) = NULL; }
|
|
||||||
#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = NULL; }
|
|
||||||
#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
|
|
||||||
|
|
||||||
class D3DTexture2D;
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
HRESULT Create(HWND wnd);
|
|
||||||
void Close();
|
|
||||||
|
|
||||||
extern ID3D11Device* device;
|
|
||||||
extern ID3D11DeviceContext* context;
|
|
||||||
extern IDXGISwapChain* swapchain;
|
|
||||||
extern bool bFrameInProgress;
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
bool BeginFrame();
|
|
||||||
void EndFrame();
|
|
||||||
void Present();
|
|
||||||
|
|
||||||
unsigned int GetBackBufferWidth();
|
|
||||||
unsigned int GetBackBufferHeight();
|
|
||||||
D3DTexture2D* &GetBackBuffer();
|
|
||||||
const char* PixelShaderVersionString();
|
|
||||||
const char* VertexShaderVersionString();
|
|
||||||
bool BGRATexturesSupported();
|
|
||||||
|
|
||||||
unsigned int GetMaxTextureSize();
|
|
||||||
|
|
||||||
// Ihis function will assign a name to the given resource.
|
|
||||||
// The DirectX debug layer will make it easier to identify resources that way,
|
|
||||||
// e.g. when listing up all resources who have unreleased references.
|
|
||||||
inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name)
|
|
||||||
{
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
resource->SetPrivateData( WKPDID_D3DDebugObjectName, (UINT)strlen(name), name);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
|
|
||||||
// Used to not require the SDK and runtime versions to match:
|
|
||||||
// Linking with d3dx11.lib makes the most recent d3dx11_xx.dll of the
|
|
||||||
// compiler's SDK a requirement, but this plugin works with DX11 runtimes
|
|
||||||
// back to August 2009 even if the plugin was built with June 2010.
|
|
||||||
// Add any d3dx11 functions which you want to use here and load them in Create()
|
|
||||||
typedef HRESULT (WINAPI* D3DX11COMPILEFROMMEMORYTYPE)(LPCSTR, SIZE_T, LPCSTR, const D3D10_SHADER_MACRO*, LPD3D10INCLUDE, LPCSTR, LPCSTR, UINT, UINT, ID3DX11ThreadPump*, ID3D10Blob**, ID3D10Blob**, HRESULT*);
|
|
||||||
typedef HRESULT (WINAPI* D3DX11FILTERTEXTURETYPE)(ID3D11DeviceContext*, ID3D11Resource*, UINT, UINT);
|
|
||||||
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEATYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCSTR);
|
|
||||||
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEWTYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCWSTR);
|
|
||||||
|
|
||||||
extern D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory;
|
|
||||||
extern D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture;
|
|
||||||
extern D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA;
|
|
||||||
extern D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW;
|
|
||||||
|
|
||||||
#ifdef UNICODE
|
|
||||||
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileW
|
|
||||||
#else
|
|
||||||
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileA
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,68 +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 "DX11_D3DBlob.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(NULL)
|
|
||||||
{
|
|
||||||
data = new u8[blob_size];
|
|
||||||
if (init_data) memcpy(data, init_data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1)
|
|
||||||
{
|
|
||||||
blob = d3dblob;
|
|
||||||
data = (u8*)blob->GetBufferPointer();
|
|
||||||
size = blob->GetBufferSize();
|
|
||||||
d3dblob->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DBlob::~D3DBlob()
|
|
||||||
{
|
|
||||||
if (blob) blob->Release();
|
|
||||||
else delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DBlob::AddRef()
|
|
||||||
{
|
|
||||||
++ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int D3DBlob::Release()
|
|
||||||
{
|
|
||||||
if (--ref == 0)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int D3DBlob::Size()
|
|
||||||
{
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* D3DBlob::Data()
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,52 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include <d3d11.h>
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
// use this class instead ID3D10Blob or ID3D11Blob whenever possible
|
|
||||||
class D3DBlob
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// memory will be copied into an own buffer
|
|
||||||
D3DBlob(unsigned int blob_size, const u8* init_data = NULL);
|
|
||||||
|
|
||||||
// d3dblob will be AddRef'd
|
|
||||||
D3DBlob(ID3D10Blob* d3dblob);
|
|
||||||
|
|
||||||
void AddRef();
|
|
||||||
unsigned int Release();
|
|
||||||
|
|
||||||
unsigned int Size();
|
|
||||||
u8* Data();
|
|
||||||
|
|
||||||
private:
|
|
||||||
~D3DBlob();
|
|
||||||
|
|
||||||
unsigned int ref;
|
|
||||||
unsigned int size;
|
|
||||||
|
|
||||||
u8* data;
|
|
||||||
ID3D10Blob* blob;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,150 +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 <d3dx11.h>
|
|
||||||
#include <d3dcompiler.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
// bytecode->shader
|
|
||||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len)
|
|
||||||
{
|
|
||||||
ID3D11VertexShader* v_shader;
|
|
||||||
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("CreateVertexShaderFromByteCode failed from %p (size %d) at %s %d\n", bytecode, len, __FILE__, __LINE__);
|
|
||||||
v_shader = NULL;
|
|
||||||
}
|
|
||||||
return v_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// code->bytecode
|
|
||||||
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
|
|
||||||
{
|
|
||||||
ID3D10Blob* shaderBuffer = NULL;
|
|
||||||
ID3D10Blob* errorBuffer = NULL;
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
|
|
||||||
#else
|
|
||||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
|
|
||||||
#endif
|
|
||||||
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::VertexShaderVersionString(),
|
|
||||||
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
|
|
||||||
|
|
||||||
if (FAILED(hr) || errorBuffer)
|
|
||||||
{
|
|
||||||
std::string msg = (char*)errorBuffer->GetBufferPointer();
|
|
||||||
msg += "\n\n";
|
|
||||||
msg += code;
|
|
||||||
MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR);
|
|
||||||
|
|
||||||
*blob = NULL;
|
|
||||||
errorBuffer->Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*blob = new D3DBlob(shaderBuffer);
|
|
||||||
shaderBuffer->Release();
|
|
||||||
}
|
|
||||||
return SUCCEEDED(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bytecode->shader
|
|
||||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len)
|
|
||||||
{
|
|
||||||
ID3D11PixelShader* p_shader;
|
|
||||||
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, NULL, &p_shader);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
|
|
||||||
p_shader = NULL;
|
|
||||||
}
|
|
||||||
return p_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// code->bytecode
|
|
||||||
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob)
|
|
||||||
{
|
|
||||||
ID3D10Blob* shaderBuffer = NULL;
|
|
||||||
ID3D10Blob* errorBuffer = NULL;
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
UINT flags = D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
|
|
||||||
#else
|
|
||||||
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
|
|
||||||
#endif
|
|
||||||
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::PixelShaderVersionString(),
|
|
||||||
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
|
|
||||||
|
|
||||||
if (FAILED(hr) || errorBuffer)
|
|
||||||
{
|
|
||||||
std::string msg = (char*)errorBuffer->GetBufferPointer();
|
|
||||||
msg += "\n\n";
|
|
||||||
msg += code;
|
|
||||||
MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR);
|
|
||||||
|
|
||||||
*blob = NULL;
|
|
||||||
errorBuffer->Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*blob = new D3DBlob(shaderBuffer);
|
|
||||||
shaderBuffer->Release();
|
|
||||||
}
|
|
||||||
return SUCCEEDED(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len)
|
|
||||||
{
|
|
||||||
D3DBlob* blob = NULL;
|
|
||||||
if (CompileVertexShader(code, len, &blob))
|
|
||||||
{
|
|
||||||
ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob);
|
|
||||||
blob->Release();
|
|
||||||
return v_shader;
|
|
||||||
}
|
|
||||||
PanicAlert("Failed to compile and create vertex shader from %p (size %d) at %s %d\n", code, len, __FILE__, __LINE__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len)
|
|
||||||
{
|
|
||||||
D3DBlob* blob = NULL;
|
|
||||||
CompilePixelShader(code, len, &blob);
|
|
||||||
if (blob)
|
|
||||||
{
|
|
||||||
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
|
|
||||||
blob->Release();
|
|
||||||
return p_shader;
|
|
||||||
}
|
|
||||||
PanicAlert("Failed to compile and create pixel shader, %s %d\n", __FILE__, __LINE__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len);
|
|
||||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len);
|
|
||||||
|
|
||||||
// The returned bytecode buffers should be Release()d.
|
|
||||||
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob);
|
|
||||||
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob);
|
|
||||||
|
|
||||||
// Utility functions
|
|
||||||
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len);
|
|
||||||
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len);
|
|
||||||
|
|
||||||
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
|
|
||||||
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
|
|
||||||
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) { return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); }
|
|
||||||
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,125 +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 <d3dx11.h>
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
|
||||||
{
|
|
||||||
if (usage == D3D11_USAGE_DYNAMIC)
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
HRESULT hr = D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
CHECK(SUCCEEDED(hr), "ID3D11DeviceContext::Map failed! (%x)", hr);
|
|
||||||
if (4 * pitch == map.RowPitch)
|
|
||||||
{
|
|
||||||
memcpy(map.pData, buffer, map.RowPitch * height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (unsigned int y = 0; y < height; ++y)
|
|
||||||
memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, map.RowPitch);
|
|
||||||
}
|
|
||||||
D3D::context->Unmap(pTexture, level);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1);
|
|
||||||
D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels)
|
|
||||||
{
|
|
||||||
ID3D11Texture2D* pTexture = NULL;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
D3D11_CPU_ACCESS_FLAG cpuflags;
|
|
||||||
if (usage == D3D11_USAGE_STAGING)
|
|
||||||
cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ);
|
|
||||||
else if (usage == D3D11_USAGE_DYNAMIC)
|
|
||||||
cpuflags = D3D11_CPU_ACCESS_WRITE;
|
|
||||||
else
|
|
||||||
cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
|
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, 1, levels, bind, usage, cpuflags);
|
|
||||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &pTexture);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
|
|
||||||
SAFE_RELEASE(pTexture);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DTexture2D::AddRef()
|
|
||||||
{
|
|
||||||
++ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT D3DTexture2D::Release()
|
|
||||||
{
|
|
||||||
--ref;
|
|
||||||
if (ref == 0)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind,
|
|
||||||
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format)
|
|
||||||
: ref(1), tex(texptr), srv(NULL), rtv(NULL), dsv(NULL)
|
|
||||||
{
|
|
||||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(D3D11_SRV_DIMENSION_TEXTURE2D, srv_format);
|
|
||||||
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D, dsv_format);
|
|
||||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(D3D11_RTV_DIMENSION_TEXTURE2D, rtv_format);
|
|
||||||
|
|
||||||
if (bind & D3D11_BIND_SHADER_RESOURCE)
|
|
||||||
D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv);
|
|
||||||
|
|
||||||
if (bind & D3D11_BIND_RENDER_TARGET)
|
|
||||||
D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv);
|
|
||||||
|
|
||||||
if (bind & D3D11_BIND_DEPTH_STENCIL)
|
|
||||||
D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv);
|
|
||||||
|
|
||||||
tex->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DTexture2D::~D3DTexture2D()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(srv);
|
|
||||||
SAFE_RELEASE(rtv);
|
|
||||||
SAFE_RELEASE(dsv);
|
|
||||||
SAFE_RELEASE(tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,60 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
class D3DTexture2D
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// there are two ways to create a D3DTexture2D object:
|
|
||||||
// either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create
|
|
||||||
// or let the texture automatically be created by D3DTexture2D::Create
|
|
||||||
|
|
||||||
D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN);
|
|
||||||
static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1);
|
|
||||||
|
|
||||||
// reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore
|
|
||||||
void AddRef();
|
|
||||||
UINT Release();
|
|
||||||
|
|
||||||
ID3D11Texture2D* &GetTex() { return tex; }
|
|
||||||
ID3D11ShaderResourceView* &GetSRV() { return srv; }
|
|
||||||
ID3D11RenderTargetView* &GetRTV() { return rtv; }
|
|
||||||
ID3D11DepthStencilView* &GetDSV() { return dsv; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
~D3DTexture2D();
|
|
||||||
|
|
||||||
ID3D11Texture2D* tex;
|
|
||||||
ID3D11ShaderResourceView* srv;
|
|
||||||
ID3D11RenderTargetView* rtv;
|
|
||||||
ID3D11DepthStencilView* dsv;
|
|
||||||
D3D11_BIND_FLAG bindflags;
|
|
||||||
UINT ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,651 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DUtil.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
CD3DFont font;
|
|
||||||
|
|
||||||
#define MAX_NUM_VERTICES 300
|
|
||||||
struct FONT2DVERTEX {
|
|
||||||
float x,y,z;
|
|
||||||
float col[4];
|
|
||||||
float tu, tv;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv)
|
|
||||||
{
|
|
||||||
FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv;
|
|
||||||
v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f;
|
|
||||||
v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f;
|
|
||||||
v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f;
|
|
||||||
v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512)
|
|
||||||
{
|
|
||||||
m_pTexture = NULL;
|
|
||||||
m_pVB = NULL;
|
|
||||||
m_InputLayout = NULL;
|
|
||||||
m_pshader = NULL;
|
|
||||||
m_vshader = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char fontpixshader[] = {
|
|
||||||
"Texture2D tex2D;\n"
|
|
||||||
"SamplerState linearSampler\n"
|
|
||||||
"{\n"
|
|
||||||
" Filter = MIN_MAG_MIP_LINEAR;\n"
|
|
||||||
" AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n"
|
|
||||||
" AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n"
|
|
||||||
" BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n"
|
|
||||||
"};\n"
|
|
||||||
"struct PS_INPUT\n"
|
|
||||||
"{\n"
|
|
||||||
" float4 pos : SV_POSITION;\n"
|
|
||||||
" float4 col : COLOR;\n"
|
|
||||||
" float2 tex : TEXCOORD;\n"
|
|
||||||
"};\n"
|
|
||||||
"float4 main( PS_INPUT input ) : SV_Target\n"
|
|
||||||
"{\n"
|
|
||||||
" return tex2D.Sample( linearSampler, input.tex ) * input.col;\n"
|
|
||||||
"};\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char fontvertshader[] = {
|
|
||||||
"struct VS_INPUT\n"
|
|
||||||
"{\n"
|
|
||||||
" float4 pos : POSITION;\n"
|
|
||||||
" float4 col : COLOR;\n"
|
|
||||||
" float2 tex : TEXCOORD;\n"
|
|
||||||
"};\n"
|
|
||||||
"struct PS_INPUT\n"
|
|
||||||
"{\n"
|
|
||||||
" float4 pos : SV_POSITION;\n"
|
|
||||||
" float4 col : COLOR;\n"
|
|
||||||
" float2 tex : TEXCOORD;\n"
|
|
||||||
"};\n"
|
|
||||||
"PS_INPUT main( VS_INPUT input )\n"
|
|
||||||
"{\n"
|
|
||||||
" PS_INPUT output;\n"
|
|
||||||
" output.pos = input.pos;\n"
|
|
||||||
" output.col = input.col;\n"
|
|
||||||
" output.tex = input.tex;\n"
|
|
||||||
" return output;\n"
|
|
||||||
"};\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
int CD3DFont::Init()
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
// prepare to create a bitmap
|
|
||||||
unsigned int* pBitmapBits;
|
|
||||||
BITMAPINFO bmi;
|
|
||||||
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
|
|
||||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
||||||
bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
|
|
||||||
bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
bmi.bmiHeader.biBitCount = 32;
|
|
||||||
|
|
||||||
// create a DC and a bitmap for the font
|
|
||||||
HDC hDC = CreateCompatibleDC(NULL);
|
|
||||||
HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
|
|
||||||
SetMapMode(hDC, MM_TEXT);
|
|
||||||
|
|
||||||
// create a GDI font
|
|
||||||
HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE,
|
|
||||||
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
|
|
||||||
CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
|
|
||||||
VARIABLE_PITCH, _T("Tahoma"));
|
|
||||||
if (NULL == hFont) return E_FAIL;
|
|
||||||
|
|
||||||
HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
|
|
||||||
HGDIOBJ hOldFont = SelectObject(hDC, hFont);
|
|
||||||
|
|
||||||
// set text properties
|
|
||||||
SetTextColor(hDC, 0xFFFFFF);
|
|
||||||
SetBkColor (hDC, 0);
|
|
||||||
SetTextAlign(hDC, TA_TOP);
|
|
||||||
|
|
||||||
TEXTMETRICW tm;
|
|
||||||
GetTextMetricsW(hDC, &tm);
|
|
||||||
m_LineHeight = tm.tmHeight;
|
|
||||||
|
|
||||||
// loop through all printable characters and output them to the bitmap
|
|
||||||
// meanwhile, keep track of the corresponding tex coords for each character.
|
|
||||||
int x = 0, y = 0;
|
|
||||||
char str[2] = "\0";
|
|
||||||
for (int c = 0; c < 127 - 32; c++)
|
|
||||||
{
|
|
||||||
str[0] = c + 32;
|
|
||||||
SIZE size;
|
|
||||||
GetTextExtentPoint32A(hDC, str, 1, &size);
|
|
||||||
if ((int)(x+size.cx+1) > m_dwTexWidth)
|
|
||||||
{
|
|
||||||
x = 0;
|
|
||||||
y += m_LineHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL);
|
|
||||||
m_fTexCoords[c][0] = (float) x /m_dwTexWidth;
|
|
||||||
m_fTexCoords[c][1] = (float) y /m_dwTexHeight;
|
|
||||||
m_fTexCoords[c][2] = (float)(x+size.cx)/m_dwTexWidth;
|
|
||||||
m_fTexCoords[c][3] = (float)(y+size.cy)/m_dwTexHeight;
|
|
||||||
|
|
||||||
x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a new texture for the font
|
|
||||||
// possible optimization: store the converted data in a buffer and fill the texture on creation.
|
|
||||||
// That way, we can use a static texture
|
|
||||||
ID3D11Texture2D* buftex;
|
|
||||||
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight,
|
|
||||||
1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC,
|
|
||||||
D3D11_CPU_ACCESS_WRITE);
|
|
||||||
hr = device->CreateTexture2D(&texdesc, NULL, &buftex);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create font texture");
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object");
|
|
||||||
|
|
||||||
// lock the surface and write the alpha values for the set pixels
|
|
||||||
D3D11_MAPPED_SUBRESOURCE texmap;
|
|
||||||
hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__);
|
|
||||||
|
|
||||||
for (y = 0; y < m_dwTexHeight; y++)
|
|
||||||
{
|
|
||||||
u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch);
|
|
||||||
for (x = 0; x < m_dwTexWidth; x++)
|
|
||||||
{
|
|
||||||
const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff);
|
|
||||||
*pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
context->Unmap(buftex, 0);
|
|
||||||
hr = D3D::device->CreateShaderResourceView(buftex, NULL, &m_pTexture);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__);
|
|
||||||
SAFE_RELEASE(buftex);
|
|
||||||
|
|
||||||
SelectObject(hDC, hOldbmBitmap);
|
|
||||||
DeleteObject(hbmBitmap);
|
|
||||||
|
|
||||||
SelectObject(hDC, hOldFont);
|
|
||||||
DeleteObject(hFont);
|
|
||||||
|
|
||||||
// setup device objects for drawing
|
|
||||||
m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader, sizeof(fontpixshader));
|
|
||||||
if (m_pshader == NULL) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object");
|
|
||||||
|
|
||||||
D3DBlob* vsbytecode;
|
|
||||||
D3D::CompileVertexShader(fontvertshader, sizeof(fontvertshader), &vsbytecode);
|
|
||||||
if (vsbytecode == NULL) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__);
|
|
||||||
m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode);
|
|
||||||
if (m_vshader == NULL) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object");
|
|
||||||
|
|
||||||
const D3D11_INPUT_ELEMENT_DESC desc[] =
|
|
||||||
{
|
|
||||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
};
|
|
||||||
hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
|
||||||
SAFE_RELEASE(vsbytecode);
|
|
||||||
|
|
||||||
D3D11_BLEND_DESC blenddesc;
|
|
||||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
|
||||||
blenddesc.IndependentBlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].BlendEnable = TRUE;
|
|
||||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
|
||||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
|
||||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
|
||||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
||||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate);
|
|
||||||
CHECK(hr==S_OK, "Create font blend state");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object");
|
|
||||||
|
|
||||||
// this might need to be changed when adding multisampling support
|
|
||||||
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false);
|
|
||||||
hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate);
|
|
||||||
CHECK(hr==S_OK, "Create font rasterizer state");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object");
|
|
||||||
|
|
||||||
D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
|
||||||
if (FAILED(hr = device->CreateBuffer(&vbdesc, NULL, &m_pVB)))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object");
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CD3DFont::Shutdown()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(m_pVB);
|
|
||||||
SAFE_RELEASE(m_pTexture);
|
|
||||||
SAFE_RELEASE(m_InputLayout);
|
|
||||||
SAFE_RELEASE(m_pshader);
|
|
||||||
SAFE_RELEASE(m_vshader);
|
|
||||||
|
|
||||||
SAFE_RELEASE(m_blendstate);
|
|
||||||
SAFE_RELEASE(m_raststate);
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const char* strText, bool center)
|
|
||||||
{
|
|
||||||
if (!m_pVB) return 0;
|
|
||||||
|
|
||||||
UINT stride = sizeof(FONT2DVERTEX);
|
|
||||||
UINT bufoffset = 0;
|
|
||||||
|
|
||||||
float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f;
|
|
||||||
float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f;
|
|
||||||
float sizeratio = size / (float)m_LineHeight;
|
|
||||||
|
|
||||||
// translate starting positions
|
|
||||||
float sx = x * scalex - 1.f;
|
|
||||||
float sy = 1.f - y * scaley;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
// fill vertex buffer
|
|
||||||
FONT2DVERTEX* pVertices;
|
|
||||||
int dwNumTriangles = 0L;
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE vbmap;
|
|
||||||
HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
|
|
||||||
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
|
|
||||||
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
|
|
||||||
|
|
||||||
// if center was requested, set current position as centre
|
|
||||||
// this is currently never used
|
|
||||||
if (center)
|
|
||||||
{
|
|
||||||
const char *oldText = strText;
|
|
||||||
float mx=0;
|
|
||||||
float maxx=0;
|
|
||||||
|
|
||||||
while (c = *strText++)
|
|
||||||
{
|
|
||||||
if (c == ('\n')) mx = 0;
|
|
||||||
if (c < (' ') ) continue;
|
|
||||||
c -= 32;
|
|
||||||
mx += (m_fTexCoords[c][2]-m_fTexCoords[c][0])/(m_fTexCoords[0][3] - m_fTexCoords[0][1]) + spacing;
|
|
||||||
if (mx > maxx) maxx = mx;
|
|
||||||
}
|
|
||||||
sx -= scalex*maxx*size;
|
|
||||||
strText = oldText;
|
|
||||||
}
|
|
||||||
// set general pipeline state
|
|
||||||
D3D::stateman->PushBlendState(m_blendstate);
|
|
||||||
D3D::stateman->PushRasterizerState(m_raststate);
|
|
||||||
D3D::stateman->Apply();
|
|
||||||
|
|
||||||
D3D::context->PSSetShader(m_pshader, NULL, 0);
|
|
||||||
D3D::context->VSSetShader(m_vshader, NULL, 0);
|
|
||||||
|
|
||||||
D3D::context->IASetInputLayout(m_InputLayout);
|
|
||||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
||||||
D3D::context->PSSetShaderResources(0, 1, &m_pTexture);
|
|
||||||
|
|
||||||
float fStartX = sx;
|
|
||||||
while (c = *strText++)
|
|
||||||
{
|
|
||||||
if (c == ('\n'))
|
|
||||||
{
|
|
||||||
sx = fStartX;
|
|
||||||
sy -= scaley * size;
|
|
||||||
}
|
|
||||||
if (c < (' ')) continue;
|
|
||||||
|
|
||||||
c -= 32;
|
|
||||||
float tx1 = m_fTexCoords[c][0];
|
|
||||||
float ty1 = m_fTexCoords[c][1];
|
|
||||||
float tx2 = m_fTexCoords[c][2];
|
|
||||||
float ty2 = m_fTexCoords[c][3];
|
|
||||||
|
|
||||||
float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio;
|
|
||||||
float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio;
|
|
||||||
|
|
||||||
FONT2DVERTEX v[6];
|
|
||||||
v[0] = InitFont2DVertex( sx, h+sy, dwColor, tx1, ty2);
|
|
||||||
v[1] = InitFont2DVertex( sx, sy, dwColor, tx1, ty1);
|
|
||||||
v[2] = InitFont2DVertex(w+sx, h+sy, dwColor, tx2, ty2);
|
|
||||||
v[3] = InitFont2DVertex(w+sx, sy, dwColor, tx2, ty1);
|
|
||||||
v[4] = v[2];
|
|
||||||
v[5] = v[1];
|
|
||||||
|
|
||||||
memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX));
|
|
||||||
|
|
||||||
pVertices+=6;
|
|
||||||
dwNumTriangles += 2;
|
|
||||||
|
|
||||||
if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
|
|
||||||
{
|
|
||||||
context->Unmap(m_pVB, 0);
|
|
||||||
|
|
||||||
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
|
|
||||||
D3D::context->Draw(3 * dwNumTriangles, 0);
|
|
||||||
|
|
||||||
dwNumTriangles = 0;
|
|
||||||
D3D11_MAPPED_SUBRESOURCE vbmap;
|
|
||||||
hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
|
|
||||||
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
|
|
||||||
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
|
|
||||||
}
|
|
||||||
sx += w + spacing * scalex * size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock and render the vertex buffer
|
|
||||||
context->Unmap(m_pVB, 0);
|
|
||||||
if (dwNumTriangles > 0)
|
|
||||||
{
|
|
||||||
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
|
|
||||||
D3D::context->Draw(3 * dwNumTriangles, 0);
|
|
||||||
}
|
|
||||||
D3D::stateman->PopBlendState();
|
|
||||||
D3D::stateman->PopRasterizerState();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11Buffer* CreateQuadVertexBuffer(unsigned int size, void* data)
|
|
||||||
{
|
|
||||||
ID3D11Buffer* vb;
|
|
||||||
D3D11_BUFFER_DESC vbdesc;
|
|
||||||
vbdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
||||||
vbdesc.ByteWidth = size;
|
|
||||||
vbdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
||||||
vbdesc.MiscFlags = 0;
|
|
||||||
vbdesc.Usage = D3D11_USAGE_DYNAMIC;
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
D3D11_SUBRESOURCE_DATA bufdata;
|
|
||||||
bufdata.pSysMem = data;
|
|
||||||
if (FAILED(device->CreateBuffer(&vbdesc, &bufdata, &vb))) return NULL;
|
|
||||||
}
|
|
||||||
else if (FAILED(device->CreateBuffer(&vbdesc, NULL, &vb))) return NULL;
|
|
||||||
|
|
||||||
return vb;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11SamplerState* linear_copy_sampler = NULL;
|
|
||||||
ID3D11SamplerState* point_copy_sampler = NULL;
|
|
||||||
ID3D11Buffer* stqvb = NULL;
|
|
||||||
ID3D11Buffer* stsqvb = NULL;
|
|
||||||
ID3D11Buffer* clearvb = NULL;
|
|
||||||
|
|
||||||
typedef struct { float x,y,z,u,v; } STQVertex;
|
|
||||||
typedef struct { float x,y,z,u,v; } STSQVertex;
|
|
||||||
typedef struct { float x,y,z; u32 col; } ClearVertex;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
float u1, v1, u2, v2;
|
|
||||||
} tex_quad_data;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
MathUtil::Rectangle<float> rdest;
|
|
||||||
float u1, v1, u2, v2;
|
|
||||||
} tex_sub_quad_data;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u32 col;
|
|
||||||
float z;
|
|
||||||
} clear_quad_data;
|
|
||||||
|
|
||||||
void InitUtils()
|
|
||||||
{
|
|
||||||
float border[4] = { 0.f, 0.f, 0.f, 0.f };
|
|
||||||
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
|
|
||||||
HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state");
|
|
||||||
|
|
||||||
samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
|
|
||||||
hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state");
|
|
||||||
|
|
||||||
// cached data used to avoid unnecessarily reloading the vertex buffers
|
|
||||||
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
|
|
||||||
memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data));
|
|
||||||
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
|
|
||||||
|
|
||||||
STQVertex stqcoords[4] = {
|
|
||||||
{-1.0f, 1.0f, 0.0f, 0, 0},
|
|
||||||
{ 1.0f, 1.0f, 0.0f, 0, 0},
|
|
||||||
{-1.0f,-1.0f, 0.0f, 0, 0},
|
|
||||||
{ 1.0f,-1.0f, 0.0f, 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
STSQVertex stsqcoords[4];
|
|
||||||
memset(stsqcoords, 0, sizeof(stsqcoords));
|
|
||||||
|
|
||||||
ClearVertex cqcoords[4] = {
|
|
||||||
{-1.0f, 1.0f, 0, 0},
|
|
||||||
{ 1.0f, 1.0f, 0, 0},
|
|
||||||
{-1.0f, -1.0f, 0, 0},
|
|
||||||
{ 1.0f, -1.0f, 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
stqvb = CreateQuadVertexBuffer(4*sizeof(STQVertex), stqcoords);
|
|
||||||
CHECK(stqvb!=NULL, "Create vertex buffer of drawShadedTexQuad");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)stqvb, "vertex buffer of drawShadedTexQuad");
|
|
||||||
|
|
||||||
stsqvb = CreateQuadVertexBuffer(4*sizeof(STSQVertex), stsqcoords);
|
|
||||||
CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad");
|
|
||||||
|
|
||||||
clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords);
|
|
||||||
CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad");
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad");
|
|
||||||
|
|
||||||
font.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShutdownUtils()
|
|
||||||
{
|
|
||||||
font.Shutdown();
|
|
||||||
SAFE_RELEASE(point_copy_sampler);
|
|
||||||
SAFE_RELEASE(linear_copy_sampler);
|
|
||||||
SAFE_RELEASE(stqvb);
|
|
||||||
SAFE_RELEASE(stsqvb);
|
|
||||||
SAFE_RELEASE(clearvb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPointCopySampler()
|
|
||||||
{
|
|
||||||
D3D::context->PSSetSamplers(0, 1, &point_copy_sampler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLinearCopySampler()
|
|
||||||
{
|
|
||||||
D3D::context->PSSetSamplers(0, 1, &linear_copy_sampler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
|
|
||||||
const D3D11_RECT* rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
ID3D11PixelShader* PShader,
|
|
||||||
ID3D11VertexShader* Vshader,
|
|
||||||
ID3D11InputLayout* layout)
|
|
||||||
{
|
|
||||||
float sw = 1.0f /(float) SourceWidth;
|
|
||||||
float sh = 1.0f /(float) SourceHeight;
|
|
||||||
float u1 = ((float)rSource->left) * sw;
|
|
||||||
float u2 = ((float)rSource->right) * sw;
|
|
||||||
float v1 = ((float)rSource->top) * sh;
|
|
||||||
float v2 = ((float)rSource->bottom) * sh;
|
|
||||||
|
|
||||||
STQVertex coords[4] = {
|
|
||||||
{-1.0f, 1.0f, 0.0f, u1, v1},
|
|
||||||
{ 1.0f, 1.0f, 0.0f, u2, v1},
|
|
||||||
{-1.0f,-1.0f, 0.0f, u1, v2},
|
|
||||||
{ 1.0f,-1.0f, 0.0f, u2, v2},
|
|
||||||
};
|
|
||||||
|
|
||||||
// only upload the data to VRAM if it changed
|
|
||||||
if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 ||
|
|
||||||
tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2)
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
D3D::context->Map(stqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, coords, sizeof(coords));
|
|
||||||
D3D::context->Unmap(stqvb, 0);
|
|
||||||
tex_quad_data.u1 = u1;
|
|
||||||
tex_quad_data.v1 = v1;
|
|
||||||
tex_quad_data.u2 = u2;
|
|
||||||
tex_quad_data.v2 = v2;
|
|
||||||
}
|
|
||||||
UINT stride = sizeof(STQVertex);
|
|
||||||
UINT offset = 0;
|
|
||||||
|
|
||||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
||||||
D3D::context->IASetInputLayout(layout);
|
|
||||||
D3D::context->IASetVertexBuffers(0, 1, &stqvb, &stride, &offset);
|
|
||||||
D3D::context->PSSetShader(PShader, NULL, 0);
|
|
||||||
D3D::context->PSSetShaderResources(0, 1, &texture);
|
|
||||||
D3D::context->VSSetShader(Vshader, NULL, 0);
|
|
||||||
D3D::stateman->Apply();
|
|
||||||
D3D::context->Draw(4, 0);
|
|
||||||
|
|
||||||
ID3D11ShaderResourceView* texres = NULL;
|
|
||||||
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
|
||||||
const MathUtil::Rectangle<float>* rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
const MathUtil::Rectangle<float>* rDest,
|
|
||||||
ID3D11PixelShader* PShader,
|
|
||||||
ID3D11VertexShader* Vshader,
|
|
||||||
ID3D11InputLayout* layout)
|
|
||||||
{
|
|
||||||
float sw = 1.0f /(float) SourceWidth;
|
|
||||||
float sh = 1.0f /(float) SourceHeight;
|
|
||||||
float u1 = (rSource->left ) * sw;
|
|
||||||
float u2 = (rSource->right ) * sw;
|
|
||||||
float v1 = (rSource->top ) * sh;
|
|
||||||
float v2 = (rSource->bottom) * sh;
|
|
||||||
|
|
||||||
STSQVertex coords[4] = {
|
|
||||||
{ rDest->left , rDest->bottom, 0.0f, u1, v1},
|
|
||||||
{ rDest->right, rDest->bottom, 0.0f, u2, v1},
|
|
||||||
{ rDest->left , rDest->top , 0.0f, u1, v2},
|
|
||||||
{ rDest->right, rDest->top , 0.0f, u2, v2},
|
|
||||||
};
|
|
||||||
|
|
||||||
// only upload the data to VRAM if it changed
|
|
||||||
if (memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(rDest)) != 0 ||
|
|
||||||
tex_sub_quad_data.u1 != u1 || tex_sub_quad_data.v1 != v1 ||
|
|
||||||
tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2)
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
D3D::context->Map(stsqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, coords, sizeof(coords));
|
|
||||||
D3D::context->Unmap(stsqvb, 0);
|
|
||||||
tex_sub_quad_data.u1 = u1;
|
|
||||||
tex_sub_quad_data.v1 = v1;
|
|
||||||
tex_sub_quad_data.u2 = u2;
|
|
||||||
tex_sub_quad_data.v2 = v2;
|
|
||||||
memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest));
|
|
||||||
}
|
|
||||||
UINT stride = sizeof(STSQVertex);
|
|
||||||
UINT offset = 0;
|
|
||||||
|
|
||||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
||||||
context->IASetVertexBuffers(0, 1, &stsqvb, &stride, &offset);
|
|
||||||
context->IASetInputLayout(layout);
|
|
||||||
context->PSSetShaderResources(0, 1, &texture);
|
|
||||||
context->PSSetShader(PShader, NULL, 0);
|
|
||||||
context->VSSetShader(Vshader, NULL, 0);
|
|
||||||
stateman->Apply();
|
|
||||||
context->Draw(4, 0);
|
|
||||||
|
|
||||||
ID3D11ShaderResourceView* texres = NULL;
|
|
||||||
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout)
|
|
||||||
{
|
|
||||||
if (clear_quad_data.col != Color || clear_quad_data.z != z)
|
|
||||||
{
|
|
||||||
const ClearVertex coords[4] = {
|
|
||||||
{-1.0f, 1.0f, z, Color},
|
|
||||||
{ 1.0f, 1.0f, z, Color},
|
|
||||||
{-1.0f, -1.0f, z, Color},
|
|
||||||
{ 1.0f, -1.0f, z, Color},
|
|
||||||
};
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
context->Map(clearvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, coords, sizeof(coords));
|
|
||||||
context->Unmap(clearvb, 0);
|
|
||||||
clear_quad_data.col = Color;
|
|
||||||
clear_quad_data.z = z;
|
|
||||||
}
|
|
||||||
context->VSSetShader(Vshader, NULL, 0);
|
|
||||||
context->PSSetShader(PShader, NULL, 0);
|
|
||||||
context->IASetInputLayout(layout);
|
|
||||||
|
|
||||||
UINT stride = sizeof(ClearVertex);
|
|
||||||
UINT offset = 0;
|
|
||||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
||||||
context->IASetVertexBuffers(0, 1, &clearvb, &stride, &offset);
|
|
||||||
stateman->Apply();
|
|
||||||
context->Draw(4, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,91 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <MathUtil.h>
|
|
||||||
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
// Font creation flags
|
|
||||||
#define D3DFONT_BOLD 0x0001
|
|
||||||
#define D3DFONT_ITALIC 0x0002
|
|
||||||
|
|
||||||
// Font rendering flags
|
|
||||||
#define D3DFONT_CENTERED 0x0001
|
|
||||||
|
|
||||||
class CD3DFont
|
|
||||||
{
|
|
||||||
ID3D11ShaderResourceView* m_pTexture;
|
|
||||||
ID3D11Buffer* m_pVB;
|
|
||||||
ID3D11InputLayout* m_InputLayout;
|
|
||||||
ID3D11PixelShader* m_pshader;
|
|
||||||
ID3D11VertexShader* m_vshader;
|
|
||||||
ID3D11BlendState* m_blendstate;
|
|
||||||
ID3D11RasterizerState* m_raststate;
|
|
||||||
const int m_dwTexWidth;
|
|
||||||
const int m_dwTexHeight;
|
|
||||||
unsigned int m_LineHeight;
|
|
||||||
float m_fTexCoords[128-32][4];
|
|
||||||
|
|
||||||
public:
|
|
||||||
CD3DFont();
|
|
||||||
// 2D text drawing function
|
|
||||||
// Initializing and destroying device-dependent objects
|
|
||||||
int Init();
|
|
||||||
int Shutdown();
|
|
||||||
int DrawTextScaled(float x, float y,
|
|
||||||
float size,
|
|
||||||
float spacing, u32 dwColor,
|
|
||||||
const char* strText, bool center=true);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CD3DFont font;
|
|
||||||
|
|
||||||
void InitUtils();
|
|
||||||
void ShutdownUtils();
|
|
||||||
|
|
||||||
void SetPointCopySampler();
|
|
||||||
void SetLinearCopySampler();
|
|
||||||
|
|
||||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
|
|
||||||
const D3D11_RECT* rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
ID3D11PixelShader* PShader,
|
|
||||||
ID3D11VertexShader* VShader,
|
|
||||||
ID3D11InputLayout* layout);
|
|
||||||
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
|
||||||
const MathUtil::Rectangle<float>* rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
const MathUtil::Rectangle<float>* rDest,
|
|
||||||
ID3D11PixelShader* PShader,
|
|
||||||
ID3D11VertexShader* Vshader,
|
|
||||||
ID3D11InputLayout* layout);
|
|
||||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout);
|
|
||||||
void SaveRenderStates();
|
|
||||||
void RestoreRenderStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,162 +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/
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
#include "DX11_D3DUtil.h"
|
|
||||||
#include "DX11_FramebufferManager.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
XFBSource FramebufferManager::m_realXFBSource; // used in real XFB mode
|
|
||||||
|
|
||||||
FramebufferManager::EFB FramebufferManager::m_efb;
|
|
||||||
|
|
||||||
D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; }
|
|
||||||
ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; }
|
|
||||||
|
|
||||||
D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; }
|
|
||||||
D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; }
|
|
||||||
ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; }
|
|
||||||
|
|
||||||
FramebufferManager::FramebufferManager()
|
|
||||||
{
|
|
||||||
m_efb.color_tex = NULL;
|
|
||||||
m_efb.color_staging_buf = NULL;
|
|
||||||
m_efb.depth_tex = NULL;
|
|
||||||
m_efb.depth_staging_buf = NULL;
|
|
||||||
m_efb.depth_read_texture = NULL;
|
|
||||||
|
|
||||||
m_realXFBSource.tex = NULL;
|
|
||||||
|
|
||||||
unsigned int target_width = Renderer::GetFullTargetWidth();
|
|
||||||
unsigned int target_height = Renderer::GetFullTargetHeight();
|
|
||||||
ID3D11Texture2D* buf;
|
|
||||||
D3D11_TEXTURE2D_DESC texdesc;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
// create framebuffer color texture
|
|
||||||
m_efb.color_tex = D3DTexture2D::Create(target_width, target_height,
|
|
||||||
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE),
|
|
||||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
CHECK(m_efb.color_tex, "create EFB color texture (size: %dx%d)", target_width, target_height);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
|
|
||||||
|
|
||||||
// create a staging texture for Renderer::AccessEFB
|
|
||||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0,
|
|
||||||
D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_WRITE|D3D11_CPU_ACCESS_READ);
|
|
||||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.color_staging_buf);
|
|
||||||
CHECK(SUCCEEDED(hr), "create EFB color staging buffer (hr=%#x)", hr);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)");
|
|
||||||
|
|
||||||
// EFB depth buffer
|
|
||||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width,
|
|
||||||
target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE);
|
|
||||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
|
||||||
CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
|
||||||
m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE),
|
|
||||||
DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT);
|
|
||||||
SAFE_RELEASE(buf);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view");
|
|
||||||
|
|
||||||
// render target for depth buffer access in Renderer::AccessEFB
|
|
||||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, D3D11_BIND_RENDER_TARGET);
|
|
||||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
|
||||||
CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr);
|
|
||||||
m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
|
||||||
SAFE_RELEASE(buf);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)");
|
|
||||||
|
|
||||||
// staging texture to which we copy the data from m_efb.depth_read_texture
|
|
||||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE);
|
|
||||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.depth_staging_buf);
|
|
||||||
CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)");
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferManager::~FramebufferManager()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(m_efb.color_tex);
|
|
||||||
SAFE_RELEASE(m_efb.color_staging_buf);
|
|
||||||
SAFE_RELEASE(m_efb.depth_tex);
|
|
||||||
SAFE_RELEASE(m_efb.depth_staging_buf);
|
|
||||||
SAFE_RELEASE(m_efb.depth_read_texture);
|
|
||||||
|
|
||||||
SAFE_RELEASE(m_realXFBSource.tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFBSource::CopyEFB(const TargetRectangle& efbSource)
|
|
||||||
{
|
|
||||||
// copy EFB data to XFB and restore render target again
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL);
|
|
||||||
D3D::SetLinearCopySampler();
|
|
||||||
|
|
||||||
D3DTexture2D* const ctex = FramebufferManager::GetEFBColorTexture();
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(ctex->GetSRV(), efbSource.AsRECT(),
|
|
||||||
Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(),
|
|
||||||
PixelShaderCache::GetColorCopyProgram(), VertexShaderCache::GetSimpleVertexShader(),
|
|
||||||
VertexShaderCache::GetSimpleInputLayout());
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &ctex->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
}
|
|
||||||
|
|
||||||
XFBSource::~XFBSource()
|
|
||||||
{
|
|
||||||
tex->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
|
||||||
{
|
|
||||||
XFBSource* const xfbs = new XFBSource;
|
|
||||||
xfbs->tex = D3DTexture2D::Create(target_width, target_height,
|
|
||||||
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
|
|
||||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
|
|
||||||
return xfbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
PanicAlert("copyToRealXFB not implemented, yet\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
||||||
{
|
|
||||||
PanicAlert("getRealXFBSource not implemented, yet\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,108 +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 _DX11_FBMANAGER_D3D_H_
|
|
||||||
#define _DX11_FBMANAGER_D3D_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
#include "../FramebufferManager.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
// On the GameCube, the game sends a request for the graphics processor to
|
|
||||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
|
||||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
|
||||||
// decided at the time of the copy, and the format is always YUYV. The video
|
|
||||||
// interface is given a pointer to the XFB, which will be decoded and
|
|
||||||
// displayed on the TV.
|
|
||||||
//
|
|
||||||
// There are two ways for Dolphin to emulate this:
|
|
||||||
//
|
|
||||||
// Real XFB mode:
|
|
||||||
//
|
|
||||||
// Dolphin will behave like the GameCube and encode the EFB to
|
|
||||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
|
||||||
// for output to the screen.
|
|
||||||
//
|
|
||||||
// Advantages: Behaves exactly like the GameCube.
|
|
||||||
// Disadvantages: Resolution will be limited.
|
|
||||||
//
|
|
||||||
// Virtual XFB mode:
|
|
||||||
//
|
|
||||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
|
||||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
|
||||||
// The video interface will look up the XFB in the list and use the enhanced
|
|
||||||
// data stored there, if available.
|
|
||||||
//
|
|
||||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
|
||||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
|
||||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
|
||||||
|
|
||||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
|
||||||
// virtualize.
|
|
||||||
|
|
||||||
struct XFBSource : public XFBSourceBase
|
|
||||||
{
|
|
||||||
XFBSource() : tex(NULL) {}
|
|
||||||
~XFBSource();
|
|
||||||
|
|
||||||
void CopyEFB(const TargetRectangle& efbSource);
|
|
||||||
|
|
||||||
D3DTexture2D* tex;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FramebufferManager : public ::FramebufferManagerBase
|
|
||||||
{
|
|
||||||
friend struct XFBSource;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FramebufferManager();
|
|
||||||
~FramebufferManager();
|
|
||||||
|
|
||||||
static D3DTexture2D* &GetEFBColorTexture();
|
|
||||||
static ID3D11Texture2D* &GetEFBColorStagingBuffer();
|
|
||||||
|
|
||||||
static D3DTexture2D* &GetEFBDepthTexture();
|
|
||||||
static D3DTexture2D* &GetEFBDepthReadTexture();
|
|
||||||
static ID3D11Texture2D* &GetEFBDepthStagingBuffer();
|
|
||||||
|
|
||||||
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
static const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
|
||||||
|
|
||||||
static XFBSource m_realXFBSource; // used in real XFB mode
|
|
||||||
|
|
||||||
static struct EFB
|
|
||||||
{
|
|
||||||
D3DTexture2D* color_tex;
|
|
||||||
ID3D11Texture2D* color_staging_buf;
|
|
||||||
|
|
||||||
D3DTexture2D* depth_tex;
|
|
||||||
ID3D11Texture2D* depth_staging_buf;
|
|
||||||
D3DTexture2D* depth_read_texture;
|
|
||||||
} m_efb;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,372 +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 "VideoConfig.h"
|
|
||||||
#include "DX11_GfxState.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
EmuGfxState* gfxstate;
|
|
||||||
StateManager* stateman;
|
|
||||||
|
|
||||||
EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(NULL), psbytecode(NULL), apply_called(false)
|
|
||||||
{
|
|
||||||
for (unsigned int k = 0;k < 8;k++)
|
|
||||||
{
|
|
||||||
float border[4] = {0.f, 0.f, 0.f, 0.f};
|
|
||||||
shader_resources[k] = NULL;
|
|
||||||
samplerdesc[k] = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, 0.f, 16, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
|
|
||||||
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&blenddesc, 0, sizeof(blenddesc));
|
|
||||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
|
||||||
blenddesc.IndependentBlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].BlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
||||||
|
|
||||||
memset(&depthdesc, 0, sizeof(depthdesc));
|
|
||||||
depthdesc.DepthEnable = TRUE;
|
|
||||||
depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
|
||||||
depthdesc.DepthFunc = D3D11_COMPARISON_LESS;
|
|
||||||
depthdesc.StencilEnable = FALSE;
|
|
||||||
depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
|
||||||
depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
|
||||||
|
|
||||||
// this probably must be changed once multisampling support gets added
|
|
||||||
rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false);
|
|
||||||
|
|
||||||
pscbuf = NULL;
|
|
||||||
vscbuf = NULL;
|
|
||||||
vshaderchanged = false;
|
|
||||||
inp_layout = NULL;
|
|
||||||
num_inp_elems = 0;
|
|
||||||
|
|
||||||
pscbufchanged = false;
|
|
||||||
vscbufchanged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmuGfxState::~EmuGfxState()
|
|
||||||
{
|
|
||||||
for (unsigned int k = 0;k < 8;k++)
|
|
||||||
SAFE_RELEASE(shader_resources[k])
|
|
||||||
|
|
||||||
SAFE_RELEASE(vsbytecode);
|
|
||||||
SAFE_RELEASE(psbytecode);
|
|
||||||
SAFE_RELEASE(vertexshader);
|
|
||||||
SAFE_RELEASE(pixelshader);
|
|
||||||
|
|
||||||
SAFE_RELEASE(pscbuf);
|
|
||||||
SAFE_RELEASE(vscbuf);
|
|
||||||
|
|
||||||
SAFE_RELEASE(inp_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: No need to store the whole bytecode, signature might be enough (?)
|
|
||||||
void EmuGfxState::SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode)
|
|
||||||
{
|
|
||||||
// TODO: vshaderchanged actually just needs to be true if the signature changed
|
|
||||||
if (bcode && vsbytecode != bcode) vshaderchanged = true;
|
|
||||||
SAFE_RELEASE(vsbytecode);
|
|
||||||
SAFE_RELEASE(vertexshader);
|
|
||||||
|
|
||||||
if (shader && bcode)
|
|
||||||
{
|
|
||||||
vertexshader = shader;
|
|
||||||
shader->AddRef();
|
|
||||||
vsbytecode = bcode;
|
|
||||||
bcode->AddRef();
|
|
||||||
}
|
|
||||||
else if (shader || bcode)
|
|
||||||
{
|
|
||||||
PanicAlert("Invalid parameters!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetPShader(ID3D11PixelShader* shader)
|
|
||||||
{
|
|
||||||
if (pixelshader) pixelshader->Release();
|
|
||||||
pixelshader = shader;
|
|
||||||
if (shader) shader->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num)
|
|
||||||
{
|
|
||||||
num_inp_elems = num;
|
|
||||||
memcpy(inp_elems, elems, num*sizeof(D3D11_INPUT_ELEMENT_DESC));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv)
|
|
||||||
{
|
|
||||||
if (shader_resources[stage])
|
|
||||||
shader_resources[stage]->Release();
|
|
||||||
shader_resources[stage] = srv;
|
|
||||||
if (srv)
|
|
||||||
srv->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::ApplyState()
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
// input layout (only needs to be updated if the vertex shader signature changed)
|
|
||||||
if (vshaderchanged)
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(inp_layout);
|
|
||||||
hr = D3D::device->CreateInputLayout(inp_elems, num_inp_elems, vsbytecode->Data(), vsbytecode->Size(), &inp_layout);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)inp_layout, "an input layout of EmuGfxState");
|
|
||||||
vshaderchanged = false;
|
|
||||||
}
|
|
||||||
D3D::context->IASetInputLayout(inp_layout);
|
|
||||||
|
|
||||||
// vertex shader
|
|
||||||
// TODO: divide the global variables of the generated shaders into about 5 constant buffers
|
|
||||||
// TODO: improve interaction between EmuGfxState and global state management, so that we don't need to set the constant buffers every time
|
|
||||||
if (!vscbuf)
|
|
||||||
{
|
|
||||||
unsigned int size = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16
|
|
||||||
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
|
||||||
hr = device->CreateBuffer(&cbdesc, NULL, &vscbuf);
|
|
||||||
CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", size);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "a vertex shader constant buffer of EmuGfxState");
|
|
||||||
}
|
|
||||||
if (vscbufchanged)
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, vsconstants, sizeof(vsconstants));
|
|
||||||
context->Unmap(vscbuf, 0);
|
|
||||||
}
|
|
||||||
D3D::context->VSSetConstantBuffers(0, 1, &vscbuf);
|
|
||||||
|
|
||||||
// pixel shader
|
|
||||||
if (!pscbuf)
|
|
||||||
{
|
|
||||||
unsigned int size = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16
|
|
||||||
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
|
||||||
device->CreateBuffer(&cbdesc, NULL, &pscbuf);
|
|
||||||
CHECK(hr==S_OK, "Create pixel shader constant buffer (size=%u)", size);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "a pixel shader constant buffer of EmuGfxState");
|
|
||||||
}
|
|
||||||
if (pscbufchanged)
|
|
||||||
{
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, psconstants, sizeof(psconstants));
|
|
||||||
context->Unmap(pscbuf, 0);
|
|
||||||
pscbufchanged = false;
|
|
||||||
}
|
|
||||||
D3D::context->PSSetConstantBuffers(0, 1, &pscbuf);
|
|
||||||
|
|
||||||
ID3D11SamplerState* samplerstate[8];
|
|
||||||
for (unsigned int stage = 0; stage < 8; stage++)
|
|
||||||
{
|
|
||||||
if (shader_resources[stage])
|
|
||||||
{
|
|
||||||
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[stage].Filter = D3D11_FILTER_ANISOTROPIC;
|
|
||||||
hr = D3D::device->CreateSamplerState(&samplerdesc[stage], &samplerstate[stage]);
|
|
||||||
if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage);
|
|
||||||
else SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "a sampler state of EmuGfxState");
|
|
||||||
}
|
|
||||||
else samplerstate[stage] = NULL;
|
|
||||||
}
|
|
||||||
D3D::context->PSSetSamplers(0, 8, samplerstate);
|
|
||||||
for (unsigned int stage = 0; stage < 8; stage++)
|
|
||||||
SAFE_RELEASE(samplerstate[stage]);
|
|
||||||
|
|
||||||
ID3D11BlendState* blstate;
|
|
||||||
hr = device->CreateBlendState(&blenddesc, &blstate);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
stateman->PushBlendState(blstate);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState");
|
|
||||||
SAFE_RELEASE(blstate);
|
|
||||||
|
|
||||||
rastdesc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
|
|
||||||
ID3D11RasterizerState* raststate;
|
|
||||||
hr = device->CreateRasterizerState(&rastdesc, &raststate);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)raststate, "a rasterizer state of EmuGfxState");
|
|
||||||
stateman->PushRasterizerState(raststate);
|
|
||||||
SAFE_RELEASE(raststate);
|
|
||||||
|
|
||||||
ID3D11DepthStencilState* depth_state;
|
|
||||||
hr = device->CreateDepthStencilState(&depthdesc, &depth_state);
|
|
||||||
if (SUCCEEDED(hr)) SetDebugObjectName((ID3D11DeviceChild*)depth_state, "a depth-stencil state of EmuGfxState");
|
|
||||||
else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
D3D::stateman->PushDepthState(depth_state);
|
|
||||||
SAFE_RELEASE(depth_state);
|
|
||||||
|
|
||||||
context->PSSetShader(pixelshader, NULL, 0);
|
|
||||||
context->VSSetShader(vertexshader, NULL, 0);
|
|
||||||
context->PSSetShaderResources(0, 8, shader_resources);
|
|
||||||
|
|
||||||
stateman->Apply();
|
|
||||||
apply_called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::AlphaPass()
|
|
||||||
{
|
|
||||||
if (!apply_called) ERROR_LOG(VIDEO, "EmuGfxState::AlphaPass called without having called ApplyState before!")
|
|
||||||
else stateman->PopBlendState();
|
|
||||||
|
|
||||||
// pixel shader for alpha pass is different, so update it
|
|
||||||
context->PSSetShader(pixelshader, NULL, 0);
|
|
||||||
|
|
||||||
ID3D11BlendState* blstate;
|
|
||||||
D3D11_BLEND_DESC desc = blenddesc;
|
|
||||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
|
||||||
desc.RenderTarget[0].BlendEnable = FALSE;
|
|
||||||
HRESULT hr = device->CreateBlendState(&desc, &blstate);
|
|
||||||
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
|
|
||||||
SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState (created during alpha pass)");
|
|
||||||
stateman->PushBlendState(blstate);
|
|
||||||
blstate->Release();
|
|
||||||
|
|
||||||
stateman->Apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::Reset()
|
|
||||||
{
|
|
||||||
for (unsigned int k = 0;k < 8;k++)
|
|
||||||
SAFE_RELEASE(shader_resources[k]);
|
|
||||||
|
|
||||||
context->PSSetShaderResources(0, 8, shader_resources); // unbind all textures
|
|
||||||
if (apply_called)
|
|
||||||
{
|
|
||||||
stateman->PopBlendState();
|
|
||||||
stateman->PopDepthState();
|
|
||||||
stateman->PopRasterizerState();
|
|
||||||
apply_called = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetAlphaBlendEnable(bool enable)
|
|
||||||
{
|
|
||||||
blenddesc.RenderTarget[0].BlendEnable = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetRenderTargetWriteMask(UINT8 mask)
|
|
||||||
{
|
|
||||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetSrcBlend(D3D11_BLEND val)
|
|
||||||
{
|
|
||||||
// TODO: Check whether e.g. the dest color check is needed here
|
|
||||||
blenddesc.RenderTarget[0].SrcBlend = val;
|
|
||||||
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
|
||||||
else blenddesc.RenderTarget[0].SrcBlendAlpha = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetDestBlend(D3D11_BLEND val)
|
|
||||||
{
|
|
||||||
// TODO: Check whether e.g. the source color check is needed here
|
|
||||||
blenddesc.RenderTarget[0].DestBlend = val;
|
|
||||||
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
|
|
||||||
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
|
||||||
else blenddesc.RenderTarget[0].DestBlendAlpha = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val)
|
|
||||||
{
|
|
||||||
blenddesc.RenderTarget[0].BlendOp = val;
|
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter)
|
|
||||||
{
|
|
||||||
samplerdesc[stage].Filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> AutoState<T>::AutoState(const T* object) : state(object)
|
|
||||||
{
|
|
||||||
((IUnknown*)state)->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> AutoState<T>::AutoState(const AutoState<T> &source)
|
|
||||||
{
|
|
||||||
state = source.GetPtr();
|
|
||||||
((T*)state)->AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> AutoState<T>::~AutoState()
|
|
||||||
{
|
|
||||||
if(state) ((T*)state)->Release();
|
|
||||||
state = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {}
|
|
||||||
|
|
||||||
void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); }
|
|
||||||
void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); }
|
|
||||||
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); }
|
|
||||||
void StateManager::PopBlendState() { blendstates.pop(); }
|
|
||||||
void StateManager::PopDepthState() { depthstates.pop(); }
|
|
||||||
void StateManager::PopRasterizerState() { raststates.pop(); }
|
|
||||||
|
|
||||||
void StateManager::Apply()
|
|
||||||
{
|
|
||||||
if (!blendstates.empty())
|
|
||||||
{
|
|
||||||
if (cur_blendstate != blendstates.top().GetPtr())
|
|
||||||
{
|
|
||||||
cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr();
|
|
||||||
D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ERROR_LOG(VIDEO, "Tried to apply without blend state!");
|
|
||||||
|
|
||||||
if (!depthstates.empty())
|
|
||||||
{
|
|
||||||
if (cur_depthstate != depthstates.top().GetPtr())
|
|
||||||
{
|
|
||||||
cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr();
|
|
||||||
D3D::context->OMSetDepthStencilState(cur_depthstate, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ERROR_LOG(VIDEO, "Tried to apply without depth state!");
|
|
||||||
|
|
||||||
if (!raststates.empty())
|
|
||||||
{
|
|
||||||
if (cur_raststate != raststates.top().GetPtr())
|
|
||||||
{
|
|
||||||
cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr();
|
|
||||||
D3D::context->RSSetState(cur_raststate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,142 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DBlob.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
// stores the pipeline state to use when calling VertexManager::Flush()
|
|
||||||
class EmuGfxState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EmuGfxState();
|
|
||||||
~EmuGfxState();
|
|
||||||
|
|
||||||
void SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode);
|
|
||||||
void SetPShader(ID3D11PixelShader* shader);
|
|
||||||
void SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num);
|
|
||||||
void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv);
|
|
||||||
|
|
||||||
void ApplyState(); // apply current state
|
|
||||||
void AlphaPass(); // only modify the current state to enable the alpha pass
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
// blend state
|
|
||||||
void SetAlphaBlendEnable(bool enable);
|
|
||||||
void SetRenderTargetWriteMask(UINT8 mask);
|
|
||||||
void SetSrcBlend(D3D11_BLEND val);
|
|
||||||
void SetDestBlend(D3D11_BLEND val);
|
|
||||||
void SetBlendOp(D3D11_BLEND_OP val);
|
|
||||||
|
|
||||||
// sampler states
|
|
||||||
void SetSamplerFilter(DWORD stage, D3D11_FILTER filter);
|
|
||||||
|
|
||||||
// TODO: add methods for changing the other states instead of modifying them directly
|
|
||||||
|
|
||||||
D3D11_SAMPLER_DESC samplerdesc[8];
|
|
||||||
D3D11_RASTERIZER_DESC rastdesc;
|
|
||||||
D3D11_DEPTH_STENCIL_DESC depthdesc;
|
|
||||||
|
|
||||||
float psconstants[C_PENVCONST_END*4];
|
|
||||||
float vsconstants[C_VENVCONST_END*4];
|
|
||||||
bool vscbufchanged;
|
|
||||||
bool pscbufchanged;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ID3D11VertexShader* vertexshader;
|
|
||||||
D3DBlob* vsbytecode;
|
|
||||||
ID3D11PixelShader* pixelshader;
|
|
||||||
D3DBlob* psbytecode;
|
|
||||||
bool vshaderchanged;
|
|
||||||
|
|
||||||
ID3D11Buffer* vscbuf;
|
|
||||||
ID3D11Buffer* pscbuf;
|
|
||||||
|
|
||||||
ID3D11InputLayout* inp_layout;
|
|
||||||
D3D11_INPUT_ELEMENT_DESC inp_elems[32];
|
|
||||||
int num_inp_elems;
|
|
||||||
|
|
||||||
ID3D11ShaderResourceView* shader_resources[8];
|
|
||||||
D3D11_BLEND_DESC blenddesc;
|
|
||||||
|
|
||||||
bool apply_called;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> class AutoState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoState(const T* object);
|
|
||||||
AutoState(const AutoState<T> &source);
|
|
||||||
~AutoState();
|
|
||||||
|
|
||||||
const inline T* GetPtr() const { return state; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const T* state;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef AutoState<ID3D11BlendState> AutoBlendState;
|
|
||||||
typedef AutoState<ID3D11DepthStencilState> AutoDepthStencilState;
|
|
||||||
typedef AutoState<ID3D11RasterizerState> AutoRasterizerState;
|
|
||||||
|
|
||||||
class StateManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StateManager();
|
|
||||||
|
|
||||||
// call any of these to change the affected states
|
|
||||||
void PushBlendState(const ID3D11BlendState* state);
|
|
||||||
void PushDepthState(const ID3D11DepthStencilState* state);
|
|
||||||
void PushRasterizerState(const ID3D11RasterizerState* state);
|
|
||||||
|
|
||||||
// call these after drawing
|
|
||||||
void PopBlendState();
|
|
||||||
void PopDepthState();
|
|
||||||
void PopRasterizerState();
|
|
||||||
|
|
||||||
// call this before any drawing operation if states could have changed meanwhile
|
|
||||||
void Apply();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::stack<AutoBlendState> blendstates;
|
|
||||||
std::stack<AutoDepthStencilState> depthstates;
|
|
||||||
std::stack<AutoRasterizerState> raststates;
|
|
||||||
ID3D11BlendState* cur_blendstate;
|
|
||||||
ID3D11DepthStencilState* cur_depthstate;
|
|
||||||
ID3D11RasterizerState* cur_raststate;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern EmuGfxState* gfxstate;
|
|
||||||
extern StateManager* stateman;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,150 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "x64Emitter.h"
|
|
||||||
#include "ABI.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "CPMemory.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_VertexManager.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
class D3DVertexFormat : public NativeVertexFormat
|
|
||||||
{
|
|
||||||
D3D11_INPUT_ELEMENT_DESC m_elems[32];
|
|
||||||
UINT m_num_elems;
|
|
||||||
|
|
||||||
public:
|
|
||||||
D3DVertexFormat() : m_num_elems(0) {}
|
|
||||||
void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
|
||||||
void SetupVertexPointers() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
|
|
||||||
{
|
|
||||||
return new D3DVertexFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
DXGI_FORMAT VarToD3D(VarType t, int size)
|
|
||||||
{
|
|
||||||
DXGI_FORMAT retval = DXGI_FORMAT_UNKNOWN;
|
|
||||||
static const DXGI_FORMAT lookup1[5] = {
|
|
||||||
DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R32_FLOAT
|
|
||||||
};
|
|
||||||
static const DXGI_FORMAT lookup2[5] = {
|
|
||||||
DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R32G32_FLOAT
|
|
||||||
};
|
|
||||||
static const DXGI_FORMAT lookup3[5] = {
|
|
||||||
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT
|
|
||||||
};
|
|
||||||
static const DXGI_FORMAT lookup4[5] = {
|
|
||||||
DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R32G32B32A32_FLOAT
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (size)
|
|
||||||
{
|
|
||||||
case 1: retval = lookup1[t]; break;
|
|
||||||
case 2: retval = lookup2[t]; break;
|
|
||||||
case 3: retval = lookup3[t]; break;
|
|
||||||
case 4: retval = lookup4[t]; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
if (retval == DXGI_FORMAT_UNKNOWN)
|
|
||||||
{
|
|
||||||
PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
|
||||||
{
|
|
||||||
vertex_stride = _vtx_decl.stride;
|
|
||||||
memset(m_elems, 0, sizeof(m_elems));
|
|
||||||
|
|
||||||
m_elems[m_num_elems].SemanticName = "POSITION";
|
|
||||||
m_elems[m_num_elems].AlignedByteOffset = 0;
|
|
||||||
m_elems[m_num_elems].Format = DXGI_FORMAT_R32G32B32_FLOAT;
|
|
||||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
|
||||||
++m_num_elems;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.normal_offset[i] > 0)
|
|
||||||
{
|
|
||||||
m_elems[m_num_elems].SemanticName = "NORMAL";
|
|
||||||
m_elems[m_num_elems].SemanticIndex = i;
|
|
||||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.normal_offset[i];
|
|
||||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size);
|
|
||||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
|
||||||
++m_num_elems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.color_offset[i] > 0)
|
|
||||||
{
|
|
||||||
m_elems[m_num_elems].SemanticName = "COLOR";
|
|
||||||
m_elems[m_num_elems].SemanticIndex = i;
|
|
||||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.color_offset[i];
|
|
||||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.color_gl_type, 4);
|
|
||||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
|
||||||
++m_num_elems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.texcoord_offset[i] > 0)
|
|
||||||
{
|
|
||||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
|
||||||
m_elems[m_num_elems].SemanticIndex = i;
|
|
||||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.texcoord_offset[i];
|
|
||||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]);
|
|
||||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
|
||||||
++m_num_elems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_vtx_decl.posmtx_offset != -1)
|
|
||||||
{
|
|
||||||
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
|
|
||||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.posmtx_offset;
|
|
||||||
m_elems[m_num_elems].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
|
||||||
++m_num_elems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DVertexFormat::SetupVertexPointers() const
|
|
||||||
{
|
|
||||||
D3D::gfxstate->SetInputElements(m_elems, m_num_elems);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,306 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "XFMemory.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
|
|
||||||
#include <D3Dcompiler.h>
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
|
||||||
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
|
|
||||||
|
|
||||||
LinearDiskCache g_ps_disk_cache;
|
|
||||||
|
|
||||||
ID3D11PixelShader* s_ColorMatrixProgram = NULL;
|
|
||||||
ID3D11PixelShader* s_ColorCopyProgram = NULL;
|
|
||||||
ID3D11PixelShader* s_DepthMatrixProgram = NULL;
|
|
||||||
ID3D11PixelShader* s_ClearProgram = NULL;
|
|
||||||
|
|
||||||
const char clear_program_code[] = {
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : SV_Target,\n"
|
|
||||||
"in float4 pos : SV_Position,\n"
|
|
||||||
"in float4 incol0 : COLOR0){\n"
|
|
||||||
"ocol0 = incol0;\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char color_copy_program_code[] = {
|
|
||||||
"sampler samp0 : register(s0);\n"
|
|
||||||
"Texture2D Tex0 : register(t0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : SV_Target,\n"
|
|
||||||
"in float4 pos : SV_Position,\n"
|
|
||||||
"in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"ocol0 = Tex0.Sample(samp0,uv0);\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char color_matrix_program_code[] = {
|
|
||||||
"sampler samp0 : register(s0);\n"
|
|
||||||
"Texture2D Tex0 : register(t0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : SV_Target,\n"
|
|
||||||
"in float4 pos : SV_Position,\n"
|
|
||||||
" in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"float4 texcol = Tex0.Sample(samp0,uv0);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char depth_matrix_program[] = {
|
|
||||||
"sampler samp0 : register(s0);\n"
|
|
||||||
"Texture2D Tex0 : register(t0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : SV_Target,\n"
|
|
||||||
" in float4 pos : SV_Position,\n"
|
|
||||||
" in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"float4 texcol = Tex0.Sample(samp0,uv0);\n"
|
|
||||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
|
|
||||||
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram()
|
|
||||||
{
|
|
||||||
return s_ColorMatrixProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram()
|
|
||||||
{
|
|
||||||
return s_DepthMatrixProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram()
|
|
||||||
{
|
|
||||||
return s_ColorCopyProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
|
|
||||||
{
|
|
||||||
return s_ClearProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK to avoid some invasive VideoCommon changes
|
|
||||||
// these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something
|
|
||||||
// offset given in floats, table index is float4
|
|
||||||
unsigned int ps_constant_offset_table[] = {
|
|
||||||
0, 4, 8, 12, // C_COLORS, 16
|
|
||||||
16, 20, 24, 28, // C_KCOLORS, 16
|
|
||||||
32, // C_ALPHA, 4
|
|
||||||
36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32
|
|
||||||
68, 72, // C_ZBIAS, 8
|
|
||||||
76, 80, // C_INDTEXSCALE, 8
|
|
||||||
84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24
|
|
||||||
108, 112, // C_FOG, 8
|
|
||||||
116, 120, 124 ,128, // C_COLORMATRIX, 16
|
|
||||||
132, 136, 140, 144, 148, // C_PLIGHTS0, 20
|
|
||||||
152, 156, 160, 164, 168, // C_PLIGHTS1, 20
|
|
||||||
172, 176, 180, 184, 188, // C_PLIGHTS2, 20
|
|
||||||
192, 196, 200, 204, 208, // C_PLIGHTS3, 20
|
|
||||||
212, 216, 220, 224, 228, // C_PLIGHTS4, 20
|
|
||||||
232, 236, 240, 244, 248, // C_PLIGHTS5, 20
|
|
||||||
252, 256, 260, 264, 268, // C_PLIGHTS6, 20
|
|
||||||
272, 276, 280, 284, 288, // C_PLIGHTS7, 20
|
|
||||||
292, 296, 300, 304, // C_PMATERIALS, 16
|
|
||||||
};
|
|
||||||
void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number] ] = f1;
|
|
||||||
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+1] = f2;
|
|
||||||
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+2] = f3;
|
|
||||||
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+3] = f4;
|
|
||||||
D3D::gfxstate->pscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float* f)
|
|
||||||
{
|
|
||||||
memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4);
|
|
||||||
D3D::gfxstate->pscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
|
|
||||||
{
|
|
||||||
memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count);
|
|
||||||
D3D::gfxstate->pscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this class will load the precompiled shaders into our cache
|
|
||||||
class PixelShaderCacheInserter : public LinearDiskCacheReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Read(const u8* key, int key_size, const u8* value, int value_size)
|
|
||||||
{
|
|
||||||
PIXELSHADERUID uid;
|
|
||||||
if (key_size != sizeof(uid)) {
|
|
||||||
ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&uid, key, key_size);
|
|
||||||
PixelShaderCache::InsertByteCode(uid, (void*)value, value_size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PixelShaderCache::PixelShaderCache()
|
|
||||||
{
|
|
||||||
// used when drawing clear quads
|
|
||||||
s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code, sizeof(clear_program_code));
|
|
||||||
CHECK(s_ClearProgram!=NULL, "Create clear pixel shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader");
|
|
||||||
|
|
||||||
// used when copying/resolving the color buffer
|
|
||||||
s_ColorCopyProgram = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code));
|
|
||||||
CHECK(s_ColorCopyProgram!=NULL, "Create color copy pixel shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color copy pixel shader");
|
|
||||||
|
|
||||||
// used for color conversion
|
|
||||||
s_ColorMatrixProgram = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code));
|
|
||||||
CHECK(s_ColorMatrixProgram!=NULL, "Create color matrix pixel shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color matrix pixel shader");
|
|
||||||
|
|
||||||
// used for depth copy
|
|
||||||
s_DepthMatrixProgram = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program));
|
|
||||||
CHECK(s_DepthMatrixProgram!=NULL, "Create depth matrix pixel shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "depth matrix pixel shader");
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
char cache_filename[MAX_PATH];
|
|
||||||
sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
|
|
||||||
PixelShaderCacheInserter inserter;
|
|
||||||
g_ps_disk_cache.OpenAndRead(cache_filename, &inserter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ONLY to be used during shutdown.
|
|
||||||
void PixelShaderCache::Clear()
|
|
||||||
{
|
|
||||||
for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++)
|
|
||||||
iter->second.Destroy();
|
|
||||||
PixelShaders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelShaderCache::~PixelShaderCache()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(s_ColorMatrixProgram);
|
|
||||||
SAFE_RELEASE(s_ColorCopyProgram);
|
|
||||||
SAFE_RELEASE(s_DepthMatrixProgram);
|
|
||||||
SAFE_RELEASE(s_ClearProgram);
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
g_ps_disk_cache.Sync();
|
|
||||||
g_ps_disk_cache.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PixelShaderCache::SetShader(bool dstAlpha)
|
|
||||||
{
|
|
||||||
PIXELSHADERUID uid;
|
|
||||||
GetPixelShaderId(&uid, dstAlpha);
|
|
||||||
|
|
||||||
// check if the shader is already set
|
|
||||||
if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount)
|
|
||||||
{
|
|
||||||
PSCache::const_iterator iter = PixelShaders.find(uid);
|
|
||||||
return (iter != PixelShaders.end() && iter->second.shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
|
|
||||||
|
|
||||||
// check if the shader is already in the cache
|
|
||||||
PSCache::iterator iter = PixelShaders.find(uid);
|
|
||||||
if (iter != PixelShaders.end())
|
|
||||||
{
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
const PSCacheEntry &entry = iter->second;
|
|
||||||
last_entry = &entry;
|
|
||||||
|
|
||||||
D3D::gfxstate->SetPShader(entry.shader);
|
|
||||||
return (entry.shader != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// need to compile a new shader
|
|
||||||
const char* code = GeneratePixelShaderCode(dstAlpha, API_D3D11);
|
|
||||||
|
|
||||||
D3DBlob* pbytecode;
|
|
||||||
if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to compile Pixel Shader:\n\n%s", code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert the bytecode into the caches
|
|
||||||
g_ps_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size());
|
|
||||||
g_ps_disk_cache.Sync();
|
|
||||||
|
|
||||||
bool result = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
|
|
||||||
D3D::gfxstate->SetPShader(last_entry->shader);
|
|
||||||
pbytecode->Release();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen)
|
|
||||||
{
|
|
||||||
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
|
||||||
if (shader == NULL)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__, __LINE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// TODO: Somehow make the debug name a bit more specific
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache");
|
|
||||||
|
|
||||||
// make an entry in the table
|
|
||||||
PSCacheEntry newentry;
|
|
||||||
newentry.shader = shader;
|
|
||||||
newentry.frameCount = frameCount;
|
|
||||||
PixelShaders[uid] = newentry;
|
|
||||||
last_entry = &PixelShaders[uid];
|
|
||||||
|
|
||||||
INCSTAT(stats.numPixelShadersCreated);
|
|
||||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,74 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
#include "../PixelShaderCache.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
class PixelShaderCache : public ::PixelShaderCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PixelShaderCache();
|
|
||||||
~PixelShaderCache();
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
bool SetShader(bool dstAlpha);
|
|
||||||
static bool InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen);
|
|
||||||
|
|
||||||
static ID3D11PixelShader* GetColorMatrixProgram();
|
|
||||||
static ID3D11PixelShader* GetColorCopyProgram();
|
|
||||||
static ID3D11PixelShader* GetDepthMatrixProgram();
|
|
||||||
static ID3D11PixelShader* GetClearProgram();
|
|
||||||
|
|
||||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetPSConstant4fv(unsigned int const_number, const float *f);
|
|
||||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct PSCacheEntry
|
|
||||||
{
|
|
||||||
ID3D11PixelShader* shader;
|
|
||||||
int frameCount;
|
|
||||||
|
|
||||||
PSCacheEntry() : shader(NULL), frameCount(0) {}
|
|
||||||
void Destroy() { SAFE_RELEASE(shader); }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
|
|
||||||
|
|
||||||
static PSCache PixelShaders;
|
|
||||||
static const PSCacheEntry* last_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,848 +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 <list>
|
|
||||||
#include <strsafe.h>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "StringUtil.h"
|
|
||||||
#include "Atomic.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "Thread.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "OnScreenDisplay.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VertexLoaderManager.h"
|
|
||||||
#include "AVIDump.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "DLCache.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DUtil.h"
|
|
||||||
#include "DX11_VertexManager.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11_TextureCache.h"
|
|
||||||
#include "DX11_FramebufferManager.h"
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
|
|
||||||
#include "../EmuWindow.h"
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
ID3D11Buffer* access_efb_cbuf = NULL;
|
|
||||||
ID3D11DepthStencilState* cleardepthstates[2] = {NULL};
|
|
||||||
ID3D11RasterizerState* clearraststate = NULL;
|
|
||||||
ID3D11BlendState* resetblendstate = NULL;
|
|
||||||
ID3D11DepthStencilState* resetdepthstate = NULL;
|
|
||||||
ID3D11RasterizerState* resetraststate = NULL;
|
|
||||||
|
|
||||||
bool reset_called = false;
|
|
||||||
|
|
||||||
// state translation lookup tables
|
|
||||||
static const D3D11_BLEND d3dSrcFactors[8] =
|
|
||||||
{
|
|
||||||
D3D11_BLEND_ZERO,
|
|
||||||
D3D11_BLEND_ONE,
|
|
||||||
D3D11_BLEND_DEST_COLOR,
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,
|
|
||||||
D3D11_BLEND_SRC_ALPHA,
|
|
||||||
D3D11_BLEND_INV_SRC_ALPHA,
|
|
||||||
D3D11_BLEND_DEST_ALPHA,
|
|
||||||
D3D11_BLEND_INV_DEST_ALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_BLEND d3dDestFactors[8] =
|
|
||||||
{
|
|
||||||
D3D11_BLEND_ZERO,
|
|
||||||
D3D11_BLEND_ONE,
|
|
||||||
D3D11_BLEND_SRC_COLOR,
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,
|
|
||||||
D3D11_BLEND_SRC_ALPHA,
|
|
||||||
D3D11_BLEND_INV_SRC_ALPHA,
|
|
||||||
D3D11_BLEND_DEST_ALPHA,
|
|
||||||
D3D11_BLEND_INV_DEST_ALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
// 0 0x00
|
|
||||||
// 1 Source & destination
|
|
||||||
// 2 Source & ~destination
|
|
||||||
// 3 Source
|
|
||||||
// 4 ~Source & destination
|
|
||||||
// 5 Destination
|
|
||||||
// 6 Source ^ destination = Source & ~destination | ~Source & destination
|
|
||||||
// 7 Source | destination
|
|
||||||
|
|
||||||
// 8 ~(Source | destination)
|
|
||||||
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
|
|
||||||
// 10 ~Destination
|
|
||||||
// 11 Source | ~destination
|
|
||||||
// 12 ~Source
|
|
||||||
// 13 ~Source | destination
|
|
||||||
// 14 ~(Source & destination)
|
|
||||||
// 15 0xff
|
|
||||||
|
|
||||||
static const D3D11_BLEND_OP d3dLogicOps[16] =
|
|
||||||
{
|
|
||||||
D3D11_BLEND_OP_ADD,//0
|
|
||||||
D3D11_BLEND_OP_ADD,//1
|
|
||||||
D3D11_BLEND_OP_SUBTRACT,//2
|
|
||||||
D3D11_BLEND_OP_ADD,//3
|
|
||||||
D3D11_BLEND_OP_REV_SUBTRACT,//4
|
|
||||||
D3D11_BLEND_OP_ADD,//5
|
|
||||||
D3D11_BLEND_OP_MAX,//6
|
|
||||||
D3D11_BLEND_OP_ADD,//7
|
|
||||||
|
|
||||||
D3D11_BLEND_OP_MAX,//8
|
|
||||||
D3D11_BLEND_OP_MAX,//9
|
|
||||||
D3D11_BLEND_OP_ADD,//10
|
|
||||||
D3D11_BLEND_OP_ADD,//11
|
|
||||||
D3D11_BLEND_OP_ADD,//12
|
|
||||||
D3D11_BLEND_OP_ADD,//13
|
|
||||||
D3D11_BLEND_OP_ADD,//14
|
|
||||||
D3D11_BLEND_OP_ADD//15
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_BLEND d3dLogicOpSrcFactors[16] =
|
|
||||||
{
|
|
||||||
D3D11_BLEND_ZERO,//0
|
|
||||||
D3D11_BLEND_DEST_COLOR,//1
|
|
||||||
D3D11_BLEND_ONE,//2
|
|
||||||
D3D11_BLEND_ONE,//3
|
|
||||||
D3D11_BLEND_DEST_COLOR,//4
|
|
||||||
D3D11_BLEND_ZERO,//5
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//6
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//7
|
|
||||||
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//8
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//9
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//10
|
|
||||||
D3D11_BLEND_ONE,//11
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//12
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//13
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//14
|
|
||||||
D3D11_BLEND_ONE//15
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_BLEND d3dLogicOpDestFactors[16] =
|
|
||||||
{
|
|
||||||
D3D11_BLEND_ZERO,//0
|
|
||||||
D3D11_BLEND_ZERO,//1
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//2
|
|
||||||
D3D11_BLEND_ZERO,//3
|
|
||||||
D3D11_BLEND_ONE,//4
|
|
||||||
D3D11_BLEND_ONE,//5
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//6
|
|
||||||
D3D11_BLEND_ONE,//7
|
|
||||||
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//8
|
|
||||||
D3D11_BLEND_SRC_COLOR,//9
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//10
|
|
||||||
D3D11_BLEND_INV_DEST_COLOR,//11
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//12
|
|
||||||
D3D11_BLEND_ONE,//13
|
|
||||||
D3D11_BLEND_INV_SRC_COLOR,//14
|
|
||||||
D3D11_BLEND_ONE//15
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_CULL_MODE d3dCullModes[4] =
|
|
||||||
{
|
|
||||||
D3D11_CULL_NONE,
|
|
||||||
D3D11_CULL_BACK,
|
|
||||||
D3D11_CULL_FRONT,
|
|
||||||
D3D11_CULL_BACK
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
|
|
||||||
{
|
|
||||||
D3D11_COMPARISON_NEVER,
|
|
||||||
D3D11_COMPARISON_LESS,
|
|
||||||
D3D11_COMPARISON_EQUAL,
|
|
||||||
D3D11_COMPARISON_LESS_EQUAL,
|
|
||||||
D3D11_COMPARISON_GREATER,
|
|
||||||
D3D11_COMPARISON_NOT_EQUAL,
|
|
||||||
D3D11_COMPARISON_GREATER_EQUAL,
|
|
||||||
D3D11_COMPARISON_ALWAYS
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TEXF_NONE 0
|
|
||||||
#define TEXF_POINT 1
|
|
||||||
#define TEXF_LINEAR 2
|
|
||||||
static const unsigned int d3dMipFilters[4] =
|
|
||||||
{
|
|
||||||
TEXF_NONE,
|
|
||||||
TEXF_POINT,
|
|
||||||
TEXF_LINEAR,
|
|
||||||
TEXF_NONE, //reserved
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
|
|
||||||
{
|
|
||||||
D3D11_TEXTURE_ADDRESS_CLAMP,
|
|
||||||
D3D11_TEXTURE_ADDRESS_WRAP,
|
|
||||||
D3D11_TEXTURE_ADDRESS_MIRROR,
|
|
||||||
D3D11_TEXTURE_ADDRESS_WRAP //reserved
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// what are these 2?
|
|
||||||
//bool Renderer::Allow2x()
|
|
||||||
//{
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//bool Renderer::AllowCustom()
|
|
||||||
//{
|
|
||||||
// return false;
|
|
||||||
//}
|
|
||||||
|
|
||||||
void Renderer::SetupDeviceObjects()
|
|
||||||
{
|
|
||||||
g_framebuffer_manager = new FramebufferManager;
|
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
float colmat[20]= {0.0f};
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = 1.0f;
|
|
||||||
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20*sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
|
||||||
D3D11_SUBRESOURCE_DATA data;
|
|
||||||
data.pSysMem = colmat;
|
|
||||||
hr = D3D::device->CreateBuffer(&cbdesc, &data, &access_efb_cbuf);
|
|
||||||
CHECK(hr==S_OK, "Create constant buffer for AccessEFB");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)access_efb_cbuf, "constant buffer for AccessEFB");
|
|
||||||
|
|
||||||
D3D11_DEPTH_STENCIL_DESC ddesc;
|
|
||||||
ddesc.DepthEnable = FALSE;
|
|
||||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
|
||||||
ddesc.StencilEnable = FALSE;
|
|
||||||
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
|
||||||
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
|
||||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]);
|
|
||||||
CHECK(hr==S_OK, "Create depth state for ClearScreen");
|
|
||||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
|
||||||
ddesc.DepthEnable = TRUE;
|
|
||||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]);
|
|
||||||
CHECK(hr==S_OK, "Create depth state for ClearScreen");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], "depth state for ClearScreen (depth buffer disabled)");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[1], "depth state for ClearScreen (depth buffer enabled)");
|
|
||||||
|
|
||||||
// TODO: once multisampling gets implemented, this might need to be changed
|
|
||||||
D3D11_RASTERIZER_DESC rdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, true, false, false);
|
|
||||||
hr = D3D::device->CreateRasterizerState(&rdesc, &clearraststate);
|
|
||||||
CHECK(hr==S_OK, "Create rasterizer state for ClearScreen");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)clearraststate, "rasterizer state for ClearScreen");
|
|
||||||
|
|
||||||
D3D11_BLEND_DESC blenddesc;
|
|
||||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
|
||||||
blenddesc.IndependentBlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].BlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
||||||
hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate);
|
|
||||||
CHECK(hr==S_OK, "Create blend state for ResetAPIState");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, "blend state for ResetAPIState");
|
|
||||||
|
|
||||||
ddesc.DepthEnable = FALSE;
|
|
||||||
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
ddesc.DepthFunc = D3D11_COMPARISON_LESS;
|
|
||||||
ddesc.StencilEnable = FALSE;
|
|
||||||
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
|
||||||
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
|
||||||
hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate);
|
|
||||||
CHECK(hr==S_OK, "Create depth state for ResetAPIState");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, "depth stencil state for ResetAPIState");
|
|
||||||
|
|
||||||
// this might need to be changed once multisampling support gets added
|
|
||||||
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false);
|
|
||||||
hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate);
|
|
||||||
CHECK(hr==S_OK, "Create rasterizer state for ClearScreen");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, "rasterizer state for ResetAPIState");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::TeardownDeviceObjects()
|
|
||||||
{
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
|
|
||||||
SAFE_RELEASE(access_efb_cbuf);
|
|
||||||
SAFE_RELEASE(cleardepthstates[0]);
|
|
||||||
SAFE_RELEASE(cleardepthstates[1]);
|
|
||||||
SAFE_RELEASE(clearraststate);
|
|
||||||
SAFE_RELEASE(resetblendstate);
|
|
||||||
SAFE_RELEASE(resetdepthstate);
|
|
||||||
SAFE_RELEASE(resetraststate);
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::Renderer()
|
|
||||||
{
|
|
||||||
UpdateActiveConfig();
|
|
||||||
|
|
||||||
//int x, y, w_temp, h_temp;
|
|
||||||
//g_VideoInitialize.pRequestWindowSize(x, y, w_temp, h_temp);
|
|
||||||
|
|
||||||
D3D::Create(EmuWindow::GetWnd());
|
|
||||||
|
|
||||||
FramebufferSize(D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight());
|
|
||||||
|
|
||||||
SetupDeviceObjects();
|
|
||||||
|
|
||||||
for (unsigned int stage = 0; stage < 8; stage++)
|
|
||||||
D3D::gfxstate->samplerdesc[stage].MaxAnisotropy = g_ActiveConfig.iMaxAnisotropy;
|
|
||||||
|
|
||||||
float ClearColor[4] = { 0.f, 0.f, 0.f, 0.f };
|
|
||||||
D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), ClearColor);
|
|
||||||
D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 1.f, 0);
|
|
||||||
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)(s_Fulltarget_width - s_target_width) / 2.f,
|
|
||||||
(float)(s_Fulltarget_height - s_target_height) / 2.f,
|
|
||||||
(float)s_target_width, (float)s_target_height);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
D3D::BeginFrame();
|
|
||||||
D3D::gfxstate->rastdesc.ScissorEnable = TRUE;
|
|
||||||
|
|
||||||
// temporary, maybe
|
|
||||||
D3D::InitUtils();
|
|
||||||
|
|
||||||
reset_called = false;
|
|
||||||
//return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::~Renderer()
|
|
||||||
{
|
|
||||||
// temporary, maybe
|
|
||||||
D3D::ShutdownUtils();
|
|
||||||
|
|
||||||
TeardownDeviceObjects();
|
|
||||||
D3D::EndFrame();
|
|
||||||
D3D::Present();
|
|
||||||
D3D::Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::CheckForResize()
|
|
||||||
{
|
|
||||||
while (EmuWindow::IsSizing())
|
|
||||||
Sleep(10);
|
|
||||||
|
|
||||||
if (EmuWindow::GetParentWnd())
|
|
||||||
{
|
|
||||||
// re-stretch window to parent window size again, if it has a parent window.
|
|
||||||
RECT rcParentWindow;
|
|
||||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow);
|
|
||||||
int width = rcParentWindow.right - rcParentWindow.left;
|
|
||||||
int height = rcParentWindow.bottom - rcParentWindow.top;
|
|
||||||
if (width != s_backbuffer_width || height != s_backbuffer_height)
|
|
||||||
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
|
||||||
}
|
|
||||||
RECT rcWindow;
|
|
||||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
|
||||||
int client_width = rcWindow.right - rcWindow.left;
|
|
||||||
int client_height = rcWindow.bottom - rcWindow.top;
|
|
||||||
|
|
||||||
// sanity check
|
|
||||||
return ((client_width != s_backbuffer_width || client_height != s_backbuffer_height) &&
|
|
||||||
client_width >= 4 && client_height >= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::SetScissorRect()
|
|
||||||
{
|
|
||||||
EFBRectangle rc;
|
|
||||||
if (g_renderer->SetScissorRect(rc))
|
|
||||||
{
|
|
||||||
D3D::context->RSSetScissorRects(1, (D3D11_RECT*)&rc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom);
|
|
||||||
const int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
const int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
rc.left = Xstride;
|
|
||||||
rc.top = Ystride;
|
|
||||||
rc.right = Xstride + s_target_width;
|
|
||||||
rc.bottom = Ystride + s_target_height;
|
|
||||||
|
|
||||||
D3D::context->RSSetScissorRects(1, (D3D11_RECT*)&rc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetColorMask()
|
|
||||||
{
|
|
||||||
UINT8 color_mask = 0;
|
|
||||||
if (bpmem.blendmode.alphaupdate)
|
|
||||||
color_mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
|
||||||
|
|
||||||
if (bpmem.blendmode.colorupdate)
|
|
||||||
color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;
|
|
||||||
|
|
||||||
D3D::gfxstate->SetRenderTargetWriteMask(color_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
|
||||||
{
|
|
||||||
ID3D11Texture2D* read_tex;
|
|
||||||
u32 ret;
|
|
||||||
|
|
||||||
if (!g_ActiveConfig.bEFBAccessEnable)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (type == POKE_Z || type == POKE_COLOR)
|
|
||||||
{
|
|
||||||
static bool alert_only_once = true;
|
|
||||||
if (!alert_only_once)
|
|
||||||
return 0;
|
|
||||||
PanicAlert("Poke EFB not implemented");
|
|
||||||
alert_only_once = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert EFB dimensions to the ones of our render target
|
|
||||||
EFBRectangle efbPixelRc;
|
|
||||||
efbPixelRc.left = x;
|
|
||||||
efbPixelRc.top = y;
|
|
||||||
efbPixelRc.right = x + 1;
|
|
||||||
efbPixelRc.bottom = y + 1;
|
|
||||||
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
|
|
||||||
|
|
||||||
// Take the mean of the resulting dimensions; TODO: check whether this causes any bugs compared to taking the average color of the target area
|
|
||||||
D3D11_RECT RectToLock;
|
|
||||||
RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2;
|
|
||||||
RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
|
||||||
RectToLock.right = RectToLock.left + 1;
|
|
||||||
RectToLock.bottom = RectToLock.top + 1;
|
|
||||||
if (type == PEEK_Z)
|
|
||||||
{
|
|
||||||
ResetAPIState(); // reset any game specific settings
|
|
||||||
|
|
||||||
// depth buffers can only be read as a whole using CopySubresourceRegion'ed, so we're using drawShadedTexQuad instead
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 4.f, 4.f);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
D3D::context->PSSetConstantBuffers(0, 1, &access_efb_cbuf);
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBDepthReadTexture()->GetRTV(), NULL);
|
|
||||||
D3D::SetPointCopySampler();
|
|
||||||
D3D::drawShadedTexQuad(FramebufferManager::GetEFBDepthTexture()->GetSRV(),
|
|
||||||
&RectToLock,
|
|
||||||
GetFullTargetWidth(),
|
|
||||||
GetFullTargetHeight(),
|
|
||||||
PixelShaderCache::GetDepthMatrixProgram(),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(),
|
|
||||||
VertexShaderCache::GetSimpleInputLayout());
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
|
|
||||||
// copy to system memory
|
|
||||||
D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1);
|
|
||||||
read_tex = FramebufferManager::GetEFBDepthStagingBuffer();
|
|
||||||
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, FramebufferManager::GetEFBDepthReadTexture()->GetTex(), 0, &box);
|
|
||||||
|
|
||||||
RestoreAPIState(); // restore game state
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we can directly copy to system memory here
|
|
||||||
read_tex = FramebufferManager::GetEFBColorStagingBuffer();
|
|
||||||
D3D11_BOX box = CD3D11_BOX(RectToLock.left, RectToLock.top, 0, RectToLock.right, RectToLock.bottom, 1);
|
|
||||||
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, FramebufferManager::GetEFBColorTexture()->GetTex(), 0, &box);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the data from system memory
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map);
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case PEEK_Z:
|
|
||||||
{
|
|
||||||
// TODO: Implement this better? Maybe we're losing precision or sth..
|
|
||||||
float val = *(float*)map.pData;
|
|
||||||
ret = (u32)(val * 0xffffff);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PEEK_COLOR:
|
|
||||||
ret = *(u32*)map.pData;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: Implement POKE_Z and POKE_COLOR
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
D3D::context->Unmap(read_tex, 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from VertexShaderManager
|
|
||||||
void Renderer::UpdateViewport()
|
|
||||||
{
|
|
||||||
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
|
|
||||||
// [0] = width/2
|
|
||||||
// [1] = height/2
|
|
||||||
// [2] = 0xFFFFFF * (farz - nearz)
|
|
||||||
// [3] = xorig + width/2 + 342
|
|
||||||
// [4] = yorig + height/2 + 342
|
|
||||||
// [5] = 0xFFFFFF * farz
|
|
||||||
const int old_fulltarget_w = s_Fulltarget_width;
|
|
||||||
const int old_fulltarget_h = s_Fulltarget_height;
|
|
||||||
|
|
||||||
int scissorXOff = bpmem.scissorOffset.x * 2;
|
|
||||||
int scissorYOff = bpmem.scissorOffset.y * 2;
|
|
||||||
|
|
||||||
float MValueX = GetTargetScaleX();
|
|
||||||
float MValueY = GetTargetScaleY();
|
|
||||||
|
|
||||||
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
int X = (int)(ceil(xfregs.rawViewport[3] - xfregs.rawViewport[0] - (scissorXOff)) * MValueX) + Xstride;
|
|
||||||
int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride;
|
|
||||||
int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX);
|
|
||||||
int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY);
|
|
||||||
if (Width < 0)
|
|
||||||
{
|
|
||||||
X += Width;
|
|
||||||
Width*=-1;
|
|
||||||
}
|
|
||||||
if (Height < 0)
|
|
||||||
{
|
|
||||||
Y += Height;
|
|
||||||
Height *= -1;
|
|
||||||
}
|
|
||||||
bool sizeChanged = false;
|
|
||||||
if (X < 0)
|
|
||||||
{
|
|
||||||
s_Fulltarget_width -= 2 * X;
|
|
||||||
X = 0;
|
|
||||||
sizeChanged=true;
|
|
||||||
}
|
|
||||||
if (Y < 0)
|
|
||||||
{
|
|
||||||
s_Fulltarget_height -= 2 * Y;
|
|
||||||
Y = 0;
|
|
||||||
sizeChanged=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float newx = (float)X;
|
|
||||||
float newy = (float)Y;
|
|
||||||
float newwidth = (float)Width;
|
|
||||||
float newheight = (float)Height;
|
|
||||||
if (sizeChanged)
|
|
||||||
{
|
|
||||||
// Make sure that the requested size is actually supported by the GFX driver
|
|
||||||
if (s_Fulltarget_width > (int)D3D::GetMaxTextureSize() || s_Fulltarget_height > (int)D3D::GetMaxTextureSize())
|
|
||||||
{
|
|
||||||
// Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least
|
|
||||||
WARNING_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D11. Requested EFB size is %dx%d\n", s_Fulltarget_width, s_Fulltarget_height);
|
|
||||||
|
|
||||||
// Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors
|
|
||||||
newx *= (float)old_fulltarget_w / (float)s_Fulltarget_width;
|
|
||||||
newy *= (float)old_fulltarget_h / (float)s_Fulltarget_height;
|
|
||||||
newwidth *= (float)old_fulltarget_w / (float)s_Fulltarget_width;
|
|
||||||
newheight *= (float)old_fulltarget_h / (float)s_Fulltarget_height;
|
|
||||||
|
|
||||||
s_Fulltarget_width = old_fulltarget_w;
|
|
||||||
s_Fulltarget_height = old_fulltarget_h;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
|
|
||||||
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
g_framebuffer_manager = new FramebufferManager;
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// some games set invalids values MinDepth and MaxDepth so fix them to the max an min allowed and let the shaders do this work
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(newx, newy, newwidth, newheight,
|
|
||||||
0.f, // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
|
|
||||||
1.f); // xfregs.rawViewport[5] / 16777216.0f;
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// color is passed in bgra order so we need to convert it to rgba
|
|
||||||
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
|
|
||||||
{
|
|
||||||
const TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
|
||||||
// update the view port for clearing the picture
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight(),
|
|
||||||
0.f,
|
|
||||||
1.f);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
|
|
||||||
// always set the scissor in case it was set by the game and has not been reset
|
|
||||||
D3D11_RECT sirc = CD3D11_RECT(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom);
|
|
||||||
D3D::context->RSSetScissorRects(1, &sirc);
|
|
||||||
u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000);
|
|
||||||
D3D::stateman->PushDepthState(cleardepthstates[zEnable]);
|
|
||||||
D3D::stateman->PushRasterizerState(clearraststate);
|
|
||||||
//D3D::stateman->PushBlendState(resetblendstate); temporarily commented until I find the cause of the blending issue in mkwii (see next line)
|
|
||||||
D3D::gfxstate->ApplyState(); // TODO (neobrain): find out whether this breaks/fixes anything or can just be dropped. Might obsolete the comment above this line
|
|
||||||
D3D::drawClearQuad(rgbaColor, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader(), VertexShaderCache::GetClearInputLayout());
|
|
||||||
D3D::gfxstate->Reset();
|
|
||||||
D3D::stateman->PopDepthState();
|
|
||||||
D3D::stateman->PopRasterizerState();
|
|
||||||
// D3D::stateman->PopBlendState();
|
|
||||||
UpdateViewport();
|
|
||||||
SetScissorRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.logicopenable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (bpmem.blendmode.subtract) // enable blending src 1 dst 1
|
|
||||||
{
|
|
||||||
D3D::gfxstate->SetAlphaBlendEnable(true);
|
|
||||||
D3D::gfxstate->SetBlendOp(D3D11_BLEND_OP_REV_SUBTRACT);
|
|
||||||
D3D::gfxstate->SetSrcBlend(d3dSrcFactors[1]);
|
|
||||||
D3D::gfxstate->SetDestBlend(d3dDestFactors[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::gfxstate->SetAlphaBlendEnable(bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)));
|
|
||||||
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)))
|
|
||||||
{
|
|
||||||
D3D::gfxstate->SetBlendOp(D3D11_BLEND_OP_ADD);
|
|
||||||
D3D::gfxstate->SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]);
|
|
||||||
D3D::gfxstate->SetDestBlend(d3dDestFactors[bpmem.blendmode.dstfactor]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect)
|
|
||||||
{
|
|
||||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_backbuffer_width, (float)s_backbuffer_height);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
static const float clear_color[4] = { 0.f, 0.f, 0.f, 1.f };
|
|
||||||
|
|
||||||
D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color);
|
|
||||||
|
|
||||||
int x = dst_rect.left;
|
|
||||||
int y = dst_rect.top;
|
|
||||||
int width = dst_rect.right - dst_rect.left;
|
|
||||||
int height = dst_rect.bottom - dst_rect.top;
|
|
||||||
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
if (y < 0) y = 0;
|
|
||||||
if (x > s_backbuffer_width) x = s_backbuffer_width;
|
|
||||||
if (y > s_backbuffer_height) y = s_backbuffer_height;
|
|
||||||
if (width < 0) width = 0;
|
|
||||||
if (height < 0) height = 0;
|
|
||||||
if (width > (s_backbuffer_width - x)) width = s_backbuffer_width - x;
|
|
||||||
if (height > (s_backbuffer_height - y)) height = s_backbuffer_height - y;
|
|
||||||
|
|
||||||
vp = CD3D11_VIEWPORT((float)x, (float)y, (float)width, (float)height);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
|
|
||||||
|
|
||||||
// activate linear filtering for the buffer copies
|
|
||||||
D3D::SetLinearCopySampler();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc)
|
|
||||||
{
|
|
||||||
if (xfbSource)
|
|
||||||
{
|
|
||||||
D3DTexture2D* const tex = ((XFBSource*)xfbSource)->tex;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
PanicAlert("DX11 XFB");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3DTexture2D* const tex = FramebufferManager::GetEFBColorTexture();
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(tex->GetSRV(), sourceRc.AsRECT(), GetFullTargetWidth(),
|
|
||||||
GetFullTargetHeight(), PixelShaderCache::GetColorCopyProgram(),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::EndFrame()
|
|
||||||
{
|
|
||||||
D3D::EndFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Present()
|
|
||||||
{
|
|
||||||
D3D::Present();
|
|
||||||
|
|
||||||
// TODO: Aren't we still holding a reference to the back buffer right now?
|
|
||||||
// TODO: this was right before getting the backbuffer size in DX11::Renderer::Swap
|
|
||||||
D3D::Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::GetBackBufferSize(int* w, int* h)
|
|
||||||
{
|
|
||||||
*w = D3D::GetBackBufferWidth();
|
|
||||||
*h = D3D::GetBackBufferHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RecreateFramebufferManger()
|
|
||||||
{
|
|
||||||
// this good?
|
|
||||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
g_framebuffer_manager = new FramebufferManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::BeginFrame()
|
|
||||||
{
|
|
||||||
D3D::BeginFrame();
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
|
|
||||||
void Renderer::ResetAPIState()
|
|
||||||
{
|
|
||||||
D3D::gfxstate->Reset();
|
|
||||||
D3D::stateman->PushBlendState(resetblendstate);
|
|
||||||
D3D::stateman->PushDepthState(resetdepthstate);
|
|
||||||
D3D::stateman->PushRasterizerState(resetraststate);
|
|
||||||
D3D::stateman->Apply();
|
|
||||||
reset_called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RestoreAPIState()
|
|
||||||
{
|
|
||||||
// gets us back into a more game-like state.
|
|
||||||
if (reset_called)
|
|
||||||
{
|
|
||||||
D3D::stateman->PopBlendState();
|
|
||||||
D3D::stateman->PopDepthState();
|
|
||||||
D3D::stateman->PopRasterizerState();
|
|
||||||
}
|
|
||||||
UpdateViewport();
|
|
||||||
SetScissorRect();
|
|
||||||
D3D::gfxstate->ApplyState();
|
|
||||||
reset_called = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
|
||||||
{
|
|
||||||
// rastdesc.FrontCounterClockwise must be false for this to work
|
|
||||||
D3D::gfxstate->rastdesc.CullMode = d3dCullModes[bpmem.genMode.cullmode];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
|
||||||
{
|
|
||||||
if (bpmem.zmode.testenable)
|
|
||||||
{
|
|
||||||
D3D::gfxstate->depthdesc.DepthEnable = TRUE;
|
|
||||||
D3D::gfxstate->depthdesc.DepthWriteMask = bpmem.zmode.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
D3D::gfxstate->depthdesc.DepthFunc = d3dCmpFuncs[bpmem.zmode.func];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::gfxstate->depthdesc.DepthEnable = FALSE;
|
|
||||||
D3D::gfxstate->depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetLogicOpMode()
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
|
||||||
{
|
|
||||||
s_blendMode = 0;
|
|
||||||
D3D::gfxstate->SetAlphaBlendEnable(true);
|
|
||||||
D3D::gfxstate->SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]);
|
|
||||||
D3D::gfxstate->SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]);
|
|
||||||
D3D::gfxstate->SetDestBlend(d3dLogicOpDestFactors[bpmem.blendmode.logicmode]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetBlendMode(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex)
|
|
||||||
{
|
|
||||||
const FourTexUnits &tex = bpmem.tex[texindex];
|
|
||||||
const TexMode0 &tm0 = tex.texMode0[stage];
|
|
||||||
const TexMode1 &tm1 = tex.texMode1[stage];
|
|
||||||
|
|
||||||
unsigned int mip;
|
|
||||||
mip = (tm0.min_filter == 8) ? TEXF_NONE : d3dMipFilters[tm0.min_filter & 3];
|
|
||||||
if ((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) mip = TEXF_NONE;
|
|
||||||
|
|
||||||
if (texindex)
|
|
||||||
stage += 4;
|
|
||||||
|
|
||||||
// TODO: Clarify whether these values are correct
|
|
||||||
// NOTE: since there's no "no filter" in DX11 we're using point filters in these cases
|
|
||||||
if (tm0.min_filter & 4) // linear min filter
|
|
||||||
{
|
|
||||||
if (tm0.mag_filter) // linear mag filter
|
|
||||||
{
|
|
||||||
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
|
||||||
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT);
|
|
||||||
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_LINEAR);
|
|
||||||
}
|
|
||||||
else // point mag filter
|
|
||||||
{
|
|
||||||
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT);
|
|
||||||
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT);
|
|
||||||
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // point min filter
|
|
||||||
{
|
|
||||||
if (tm0.mag_filter) // linear mag filter
|
|
||||||
{
|
|
||||||
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT);
|
|
||||||
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT);
|
|
||||||
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR);
|
|
||||||
}
|
|
||||||
else // point mag filter
|
|
||||||
{
|
|
||||||
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_POINT);
|
|
||||||
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_POINT);
|
|
||||||
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::gfxstate->samplerdesc[stage].AddressU = d3dClamps[tm0.wrap_s];
|
|
||||||
D3D::gfxstate->samplerdesc[stage].AddressV = d3dClamps[tm0.wrap_t];
|
|
||||||
|
|
||||||
D3D::gfxstate->samplerdesc[stage].MipLODBias = (float)tm0.lod_bias / 32.0f;
|
|
||||||
D3D::gfxstate->samplerdesc[stage].MaxLOD = (float)tm1.max_lod / 16.f;
|
|
||||||
D3D::gfxstate->samplerdesc[stage].MinLOD = (float)tm1.min_lod / 16.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MathUtil.h"
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
class Renderer : public ::RendererBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Renderer();
|
|
||||||
~Renderer();
|
|
||||||
|
|
||||||
// What's the real difference between these? Too similar names.
|
|
||||||
void ResetAPIState();
|
|
||||||
void RestoreAPIState();
|
|
||||||
|
|
||||||
static void SetupDeviceObjects();
|
|
||||||
static void TeardownDeviceObjects();
|
|
||||||
|
|
||||||
void SetColorMask();
|
|
||||||
void SetBlendMode(bool forceUpdate);
|
|
||||||
bool SetScissorRect();
|
|
||||||
|
|
||||||
void SetGenerationMode();
|
|
||||||
void SetDepthMode();
|
|
||||||
void SetLogicOpMode();
|
|
||||||
void SetSamplerState(int stage,int texindex);
|
|
||||||
|
|
||||||
u32 AccessEFB(EFBAccessType type, int x, int y);
|
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
|
||||||
void UpdateViewport();
|
|
||||||
|
|
||||||
// virtual funcs used by RendererBase::Swap
|
|
||||||
void PrepareXFBCopy(const TargetRectangle &dst_rect);
|
|
||||||
void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc);
|
|
||||||
void EndFrame();
|
|
||||||
void Present();
|
|
||||||
bool CheckForResize();
|
|
||||||
void GetBackBufferSize(int* w, int* h);
|
|
||||||
void RecreateFramebufferManger();
|
|
||||||
void BeginFrame();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,230 +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 <d3dx11.h>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "CommonPaths.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "Hash.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "TextureDecoder.h"
|
|
||||||
#include "HiresTextures.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
#include "DX11_D3DUtil.h"
|
|
||||||
#include "DX11_FramebufferManager.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_TextureCache.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
ID3D11BlendState* efbcopyblendstate = NULL;
|
|
||||||
ID3D11RasterizerState* efbcopyraststate = NULL;
|
|
||||||
ID3D11DepthStencilState* efbcopydepthstate = NULL;
|
|
||||||
ID3D11Buffer* efbcopycbuf[20] = {};
|
|
||||||
|
|
||||||
TextureCache::TCacheEntry::~TCacheEntry()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int level)
|
|
||||||
{
|
|
||||||
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
// stretch picture with increased internal resolution
|
|
||||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)Scaledw, (float)Scaledh);
|
|
||||||
D3D::context->RSSetViewports(1, &vp);
|
|
||||||
|
|
||||||
// set transformation
|
|
||||||
if (NULL == efbcopycbuf[cbufid])
|
|
||||||
{
|
|
||||||
const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
|
||||||
D3D11_SUBRESOURCE_DATA data;
|
|
||||||
data.pSysMem = colmat;
|
|
||||||
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
|
|
||||||
CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
|
|
||||||
}
|
|
||||||
D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]);
|
|
||||||
|
|
||||||
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect);
|
|
||||||
// TODO: try targetSource.asRECT();
|
|
||||||
const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
|
|
||||||
|
|
||||||
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
|
|
||||||
if (bScaleByHalf)
|
|
||||||
D3D::SetLinearCopySampler();
|
|
||||||
else
|
|
||||||
D3D::SetPointCopySampler();
|
|
||||||
|
|
||||||
D3D::stateman->PushBlendState(efbcopyblendstate);
|
|
||||||
D3D::stateman->PushRasterizerState(efbcopyraststate);
|
|
||||||
D3D::stateman->PushDepthState(efbcopydepthstate);
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL);
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(
|
|
||||||
(bFromZBuffer) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(),
|
|
||||||
&sourcerect, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(),
|
|
||||||
(bFromZBuffer) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
|
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
|
||||||
|
|
||||||
D3D::stateman->PopBlendState();
|
|
||||||
D3D::stateman->PopDepthState();
|
|
||||||
D3D::stateman->PopRasterizerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
|
||||||
{
|
|
||||||
D3D::gfxstate->SetShaderResource(stage, texture->GetSRV());
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
|
||||||
unsigned int height, unsigned int expanded_width,
|
|
||||||
unsigned int tex_levels, PC_TexFormat pcfmt)
|
|
||||||
{
|
|
||||||
D3D11_SUBRESOURCE_DATA srdata;
|
|
||||||
|
|
||||||
D3D11_SUBRESOURCE_DATA *data = NULL;
|
|
||||||
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
|
|
||||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
|
||||||
|
|
||||||
// TODO: temp
|
|
||||||
tex_levels = 1;
|
|
||||||
|
|
||||||
if (1 == tex_levels)
|
|
||||||
{
|
|
||||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
|
||||||
usage = D3D11_USAGE_DYNAMIC;
|
|
||||||
|
|
||||||
srdata.pSysMem = temp;
|
|
||||||
srdata.SysMemPitch = 4 * expanded_width;
|
|
||||||
data = &srdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
||||||
width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
|
|
||||||
|
|
||||||
ID3D11Texture2D *pTexture;
|
|
||||||
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
|
|
||||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
|
||||||
|
|
||||||
TCacheEntry* const entry = new TCacheEntry(new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
|
|
||||||
entry->usage = usage;
|
|
||||||
|
|
||||||
// TODO: silly debug names
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
|
|
||||||
|
|
||||||
// wuts this?
|
|
||||||
//if (0 == tex_levels)
|
|
||||||
// PD3DX11FilterTexture(D3D::context, entry->texture->GetTex(), 0, D3DX11_DEFAULT);
|
|
||||||
|
|
||||||
// TODO: this good?
|
|
||||||
//if (1 != tex_levels)
|
|
||||||
// entry->Load(width, height, expanded_width, 0);
|
|
||||||
|
|
||||||
SAFE_RELEASE(pTexture);
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h)
|
|
||||||
{
|
|
||||||
return new TCacheEntry(D3DTexture2D::Create(scaled_tex_w, scaled_tex_h,
|
|
||||||
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
|
|
||||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM));
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TextureCache()
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
D3D11_BLEND_DESC blenddesc;
|
|
||||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
|
||||||
blenddesc.IndependentBlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].BlendEnable = FALSE;
|
|
||||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
||||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
||||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
||||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
||||||
hr = D3D::device->CreateBlendState(&blenddesc, &efbcopyblendstate);
|
|
||||||
CHECK(hr==S_OK, "Create blend state for CopyRenderTargetToTexture");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyblendstate, "blend state used in CopyRenderTargetToTexture");
|
|
||||||
|
|
||||||
D3D11_DEPTH_STENCIL_DESC depthdesc;
|
|
||||||
depthdesc.DepthEnable = FALSE;
|
|
||||||
depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
|
||||||
depthdesc.DepthFunc = D3D11_COMPARISON_LESS;
|
|
||||||
depthdesc.StencilEnable = FALSE;
|
|
||||||
depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
|
||||||
depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
|
||||||
hr = D3D::device->CreateDepthStencilState(&depthdesc, &efbcopydepthstate);
|
|
||||||
CHECK(hr==S_OK, "Create depth state for CopyRenderTargetToTexture");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopydepthstate, "depth stencil state used in CopyRenderTargetToTexture");
|
|
||||||
|
|
||||||
D3D11_RASTERIZER_DESC rastdesc;
|
|
||||||
rastdesc.CullMode = D3D11_CULL_NONE;
|
|
||||||
rastdesc.FillMode = D3D11_FILL_SOLID;
|
|
||||||
rastdesc.FrontCounterClockwise = false;
|
|
||||||
rastdesc.DepthBias = false;
|
|
||||||
rastdesc.DepthBiasClamp = 0;
|
|
||||||
rastdesc.SlopeScaledDepthBias = 0;
|
|
||||||
rastdesc.DepthClipEnable = false;
|
|
||||||
rastdesc.ScissorEnable = false;
|
|
||||||
rastdesc.MultisampleEnable = false;
|
|
||||||
rastdesc.AntialiasedLineEnable = false;
|
|
||||||
hr = D3D::device->CreateRasterizerState(&rastdesc, &efbcopyraststate);
|
|
||||||
CHECK(hr==S_OK, "Create rasterizer state for CopyRenderTargetToTexture");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyraststate, "rasterizer state used in CopyRenderTargetToTexture");
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::~TextureCache()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(efbcopyblendstate);
|
|
||||||
SAFE_RELEASE(efbcopyraststate);
|
|
||||||
SAFE_RELEASE(efbcopydepthstate);
|
|
||||||
|
|
||||||
for (unsigned int k = 0; k < 20; ++k)
|
|
||||||
SAFE_RELEASE(efbcopycbuf[k]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,66 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DTexture.h"
|
|
||||||
|
|
||||||
#include "../TextureCache.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
class TextureCache : public ::TextureCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct TCacheEntry : TCacheEntryBase
|
|
||||||
{
|
|
||||||
D3DTexture2D* texture;
|
|
||||||
|
|
||||||
D3D11_USAGE usage;
|
|
||||||
|
|
||||||
TCacheEntry(D3DTexture2D* _texture) : texture(_texture) {}
|
|
||||||
~TCacheEntry();
|
|
||||||
|
|
||||||
void Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int level);
|
|
||||||
|
|
||||||
void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect);
|
|
||||||
|
|
||||||
void Bind(unsigned int stage);
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureCache();
|
|
||||||
~TextureCache();
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h);
|
|
||||||
|
|
||||||
void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source_rect);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,194 +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 <string>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "IndexGenerator.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
#include "NativeVertexWriter.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
#include "DX11_D3DUtil.h"
|
|
||||||
#include "DX11_VertexManager.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11_TextureCache.h"
|
|
||||||
#include "DX11_FramebufferManager.h"
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
//using std::string;
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace D3D;
|
|
||||||
|
|
||||||
ID3D11Buffer* indexbuffers[NUM_INDEXBUFFERS] = {};
|
|
||||||
ID3D11Buffer* vertexbuffers[NUM_VERTEXBUFFERS] = {};
|
|
||||||
|
|
||||||
// TODO: these seem ugly
|
|
||||||
inline ID3D11Buffer* GetSuitableIndexBuffer(const u32 minsize)
|
|
||||||
{
|
|
||||||
for (u32 k = 0; k < NUM_INDEXBUFFERS - 1; ++k)
|
|
||||||
if (minsize > (((u32)MAXIBUFFERSIZE) >> k))
|
|
||||||
return indexbuffers[k];
|
|
||||||
return indexbuffers[NUM_INDEXBUFFERS - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ID3D11Buffer* GetSuitableVertexBuffer(const u32 minsize)
|
|
||||||
{
|
|
||||||
for (u32 k = 0; k < NUM_VERTEXBUFFERS - 1; ++k)
|
|
||||||
if (minsize > (((u32)MAXVBUFFERSIZE) >> (k + 1)))
|
|
||||||
return vertexbuffers[k];
|
|
||||||
return vertexbuffers[NUM_VERTEXBUFFERS - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateDeviceObjects()
|
|
||||||
{
|
|
||||||
D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAXIBUFFERSIZE * 2,
|
|
||||||
D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
|
||||||
for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1)
|
|
||||||
{
|
|
||||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, indexbuffers + k)),
|
|
||||||
"Failed to create index buffer [%i].", k);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)indexbuffers[k], "an index buffer of VertexManager");
|
|
||||||
}
|
|
||||||
|
|
||||||
bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
||||||
bufdesc.ByteWidth = MAXVBUFFERSIZE;
|
|
||||||
for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1)
|
|
||||||
{
|
|
||||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, vertexbuffers + k)),
|
|
||||||
"Failed to create vertex buffer [%i].", k);
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)vertexbuffers[k], "a vertex buffer of VertexManager");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroyDeviceObjects()
|
|
||||||
{
|
|
||||||
for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k)
|
|
||||||
SAFE_RELEASE(indexbuffers[k]);
|
|
||||||
|
|
||||||
for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k)
|
|
||||||
SAFE_RELEASE(vertexbuffers[k]);
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexManager::VertexManager()
|
|
||||||
{
|
|
||||||
CreateDeviceObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexManager::~VertexManager()
|
|
||||||
{
|
|
||||||
DestroyDeviceObjects();
|
|
||||||
ResetBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManager::Draw(u32 stride, bool alphapass)
|
|
||||||
{
|
|
||||||
static const UINT bufoffset = 0;
|
|
||||||
const UINT bufstride = stride;
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
|
||||||
ID3D11Buffer* const vertexbuffer = GetSuitableVertexBuffer((u32)(s_pCurBufferPointer - LocalVBuffer));
|
|
||||||
|
|
||||||
if (alphapass)
|
|
||||||
{
|
|
||||||
gfxstate->AlphaPass();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context->Map(vertexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, LocalVBuffer, (u32)(s_pCurBufferPointer - LocalVBuffer));
|
|
||||||
context->Unmap(vertexbuffer, 0);
|
|
||||||
|
|
||||||
gfxstate->ApplyState();
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::context->IASetVertexBuffers(0, 1, &vertexbuffer, &bufstride, &bufoffset);
|
|
||||||
|
|
||||||
if (IndexGenerator::GetNumTriangles() > 0)
|
|
||||||
{
|
|
||||||
u32 indexbuffersize = IndexGenerator::GetTriangleindexLen();
|
|
||||||
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
|
|
||||||
if (!alphapass)
|
|
||||||
{
|
|
||||||
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, TIBuffer, 2*indexbuffersize);
|
|
||||||
D3D::context->Unmap(indexbuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
||||||
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
|
|
||||||
|
|
||||||
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumLines() > 0)
|
|
||||||
{
|
|
||||||
u32 indexbuffersize = IndexGenerator::GetLineindexLen();
|
|
||||||
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
|
|
||||||
if (!alphapass)
|
|
||||||
{
|
|
||||||
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, LIBuffer, 2*indexbuffersize);
|
|
||||||
D3D::context->Unmap(indexbuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
|
|
||||||
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
|
|
||||||
|
|
||||||
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumPoints() > 0)
|
|
||||||
{
|
|
||||||
u32 indexbuffersize = IndexGenerator::GetPointindexLen();
|
|
||||||
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
|
|
||||||
if (!alphapass)
|
|
||||||
{
|
|
||||||
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
|
||||||
memcpy(map.pData, PIBuffer, 2*indexbuffersize);
|
|
||||||
D3D::context->Unmap(indexbuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
|
|
||||||
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
|
|
||||||
|
|
||||||
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,49 +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 _DX11_VERTEXMANAGER_H
|
|
||||||
#define _DX11_VERTEXMANAGER_H
|
|
||||||
|
|
||||||
#include "CPMemory.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
|
|
||||||
#include "../VertexManager.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
// TODO: find sensible values for these two
|
|
||||||
NUM_VERTEXBUFFERS = 8,
|
|
||||||
NUM_INDEXBUFFERS = 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
class VertexManager : public ::VertexManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VertexManager();
|
|
||||||
~VertexManager();
|
|
||||||
|
|
||||||
void Draw(u32 stride, bool alphapass);
|
|
||||||
|
|
||||||
NativeVertexFormat* CreateNativeVertexFormat();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,283 +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 <map>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "XFMemory.h"
|
|
||||||
|
|
||||||
// DX11
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
#include "DX11_D3DShader.h"
|
|
||||||
#include "DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11_Render.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
|
||||||
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
|
|
||||||
|
|
||||||
static ID3D11VertexShader* SimpleVertexShader = NULL;
|
|
||||||
static ID3D11VertexShader* ClearVertexShader = NULL;
|
|
||||||
static ID3D11InputLayout* SimpleLayout = NULL;
|
|
||||||
static ID3D11InputLayout* ClearLayout = NULL;
|
|
||||||
|
|
||||||
LinearDiskCache g_vs_disk_cache;
|
|
||||||
|
|
||||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
|
|
||||||
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
|
|
||||||
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; }
|
|
||||||
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; }
|
|
||||||
|
|
||||||
// maps the constant numbers to float indices in the constant buffer
|
|
||||||
unsigned int vs_constant_offset_table[C_VENVCONST_END];
|
|
||||||
void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number] ] = f1;
|
|
||||||
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+1] = f2;
|
|
||||||
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+2] = f3;
|
|
||||||
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+3] = f4;
|
|
||||||
D3D::gfxstate->vscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float* f)
|
|
||||||
{
|
|
||||||
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4);
|
|
||||||
D3D::gfxstate->vscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3);
|
|
||||||
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f;
|
|
||||||
}
|
|
||||||
D3D::gfxstate->vscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
|
|
||||||
{
|
|
||||||
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count);
|
|
||||||
D3D::gfxstate->vscbufchanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this class will load the precompiled shaders into our cache
|
|
||||||
class VertexShaderCacheInserter : public LinearDiskCacheReader {
|
|
||||||
public:
|
|
||||||
void Read(const u8* key, int key_size, const u8* value, int value_size)
|
|
||||||
{
|
|
||||||
VERTEXSHADERUID uid;
|
|
||||||
if (key_size != sizeof(uid))
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&uid, key, key_size);
|
|
||||||
|
|
||||||
D3DBlob* blob = new D3DBlob(value_size, value);
|
|
||||||
VertexShaderCache::InsertByteCode(uid, blob);
|
|
||||||
blob->Release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const char simple_shader_code[] = {
|
|
||||||
"struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float2 vTexCoord : TEXCOORD0;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;\n"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vTexCoord = inTEX0;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char clear_shader_code[] = {
|
|
||||||
"struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float4 vColor0 : COLOR0;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;\n"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vColor0 = inColor0;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
VertexShaderCache::VertexShaderCache()
|
|
||||||
{
|
|
||||||
const D3D11_INPUT_ELEMENT_DESC simpleelems[2] =
|
|
||||||
{
|
|
||||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
};
|
|
||||||
const D3D11_INPUT_ELEMENT_DESC clearelems[2] =
|
|
||||||
{
|
|
||||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
D3DBlob* blob;
|
|
||||||
D3D::CompileVertexShader(simple_shader_code, sizeof(simple_shader_code), &blob);
|
|
||||||
D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout);
|
|
||||||
SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
|
||||||
if (SimpleLayout == NULL || SimpleVertexShader == NULL) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
|
|
||||||
blob->Release();
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout");
|
|
||||||
|
|
||||||
D3D::CompileVertexShader(clear_shader_code, sizeof(clear_shader_code), &blob);
|
|
||||||
D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout);
|
|
||||||
ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
|
||||||
if (ClearLayout == NULL || ClearVertexShader == NULL) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
|
|
||||||
blob->Release();
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader");
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout");
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
// these values are hardcoded, they depend on internal D3DCompile behavior
|
|
||||||
// TODO: Do this with D3DReflect or something instead
|
|
||||||
unsigned int k;
|
|
||||||
for (k = 0;k < 6;k++) vs_constant_offset_table[C_POSNORMALMATRIX+k] = 0+4*k;
|
|
||||||
for (k = 0;k < 4;k++) vs_constant_offset_table[C_PROJECTION+k] = 24+4*k;
|
|
||||||
for (k = 0;k < 4;k++) vs_constant_offset_table[C_MATERIALS+k] = 40+4*k;
|
|
||||||
for (k = 0;k < 40;k++) vs_constant_offset_table[C_LIGHTS+k] = 56+4*k;
|
|
||||||
for (k = 0;k < 24;k++) vs_constant_offset_table[C_TEXMATRICES+k] = 216+4*k;
|
|
||||||
for (k = 0;k < 64;k++) vs_constant_offset_table[C_TRANSFORMMATRICES+k] = 312+4*k;
|
|
||||||
for (k = 0;k < 32;k++) vs_constant_offset_table[C_NORMALMATRICES+k] = 568+4*k;
|
|
||||||
for (k = 0;k < 64;k++) vs_constant_offset_table[C_POSTTRANSFORMMATRICES+k] = 696+4*k;
|
|
||||||
for (k = 0;k < 4;k++) vs_constant_offset_table[C_DEPTHPARAMS+k] = 952+4*k;
|
|
||||||
|
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
char cache_filename[MAX_PATH];
|
|
||||||
sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
|
|
||||||
VertexShaderCacheInserter inserter;
|
|
||||||
g_vs_disk_cache.OpenAndRead(cache_filename, &inserter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::Clear()
|
|
||||||
{
|
|
||||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
|
|
||||||
iter->second.Destroy();
|
|
||||||
vshaders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexShaderCache::~VertexShaderCache()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(SimpleVertexShader);
|
|
||||||
SAFE_RELEASE(ClearVertexShader);
|
|
||||||
|
|
||||||
SAFE_RELEASE(SimpleLayout);
|
|
||||||
SAFE_RELEASE(ClearLayout);
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
g_vs_disk_cache.Sync();
|
|
||||||
g_vs_disk_cache.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VertexShaderCache::SetShader(u32 components)
|
|
||||||
{
|
|
||||||
DVSTARTPROFILE();
|
|
||||||
|
|
||||||
VERTEXSHADERUID uid;
|
|
||||||
GetVertexShaderId(&uid, components);
|
|
||||||
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
|
|
||||||
return (vshaders[uid].shader != NULL);
|
|
||||||
|
|
||||||
memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID));
|
|
||||||
|
|
||||||
VSCache::iterator iter;
|
|
||||||
iter = vshaders.find(uid);
|
|
||||||
if (iter != vshaders.end())
|
|
||||||
{
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
const VSCacheEntry &entry = iter->second;
|
|
||||||
last_entry = &entry;
|
|
||||||
|
|
||||||
if (entry.shader) D3D::gfxstate->SetVShader(entry.shader, iter->second.bytecode);
|
|
||||||
return (entry.shader != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* code = GenerateVertexShaderCode(components, API_D3D11);
|
|
||||||
|
|
||||||
D3DBlob* pbytecode = NULL;
|
|
||||||
D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode);
|
|
||||||
|
|
||||||
if (pbytecode == NULL)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to compile Vertex Shader %s %d:\n\n%s", __FILE__, __LINE__, code);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
g_vs_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size());
|
|
||||||
g_vs_disk_cache.Sync();
|
|
||||||
|
|
||||||
bool result = InsertByteCode(uid, pbytecode);
|
|
||||||
D3D::gfxstate->SetVShader(last_entry->shader, last_entry->bytecode);
|
|
||||||
pbytecode->Release();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob)
|
|
||||||
{
|
|
||||||
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
|
|
||||||
if (shader == NULL)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create vertex shader from %p size %d at %s %d\n", bcodeblob->Data(), bcodeblob->Size(), __FILE__, __LINE__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// TODO: Somehow make the debug name a bit more specific
|
|
||||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
|
|
||||||
|
|
||||||
// Make an entry in the table
|
|
||||||
VSCacheEntry entry;
|
|
||||||
entry.shader = shader;
|
|
||||||
entry.frameCount = frameCount;
|
|
||||||
entry.SetByteCode(bcodeblob);
|
|
||||||
|
|
||||||
vshaders[uid] = entry;
|
|
||||||
last_entry = &vshaders[uid];
|
|
||||||
|
|
||||||
INCSTAT(stats.numVertexShadersCreated);
|
|
||||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +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 _DX11_VERTEXSHADERCACHE_H
|
|
||||||
#define _DX11_VERTEXSHADERCACHE_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "DX11_D3DBase.h"
|
|
||||||
|
|
||||||
#include "../VertexShaderCache.h"
|
|
||||||
|
|
||||||
namespace DX11
|
|
||||||
{
|
|
||||||
|
|
||||||
class VertexShaderCache : public ::VertexShaderCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VertexShaderCache();
|
|
||||||
~VertexShaderCache();
|
|
||||||
|
|
||||||
static void Clear();
|
|
||||||
bool SetShader(u32 components);
|
|
||||||
|
|
||||||
static ID3D11VertexShader* GetSimpleVertexShader();
|
|
||||||
static ID3D11VertexShader* GetClearVertexShader();
|
|
||||||
static ID3D11InputLayout* GetSimpleInputLayout();
|
|
||||||
static ID3D11InputLayout* GetClearInputLayout();
|
|
||||||
|
|
||||||
static bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob);
|
|
||||||
|
|
||||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetVSConstant4fv(unsigned int const_number, const float* f);
|
|
||||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f);
|
|
||||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct VSCacheEntry
|
|
||||||
{
|
|
||||||
ID3D11VertexShader* shader;
|
|
||||||
D3DBlob* bytecode; // needed to initialize the input layout
|
|
||||||
int frameCount;
|
|
||||||
|
|
||||||
VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {}
|
|
||||||
void SetByteCode(D3DBlob* blob)
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(bytecode);
|
|
||||||
bytecode = blob;
|
|
||||||
blob->AddRef();
|
|
||||||
}
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(shader);
|
|
||||||
SAFE_RELEASE(bytecode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef std::map<VERTEXSHADERUID, VSCacheEntry> VSCache;
|
|
||||||
|
|
||||||
static VSCache vshaders;
|
|
||||||
static const VSCacheEntry* last_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _VERTEXSHADERCACHE_H
|
|
|
@ -1,730 +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 "DX9_D3DBase.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
#include "StringUtil.h"
|
|
||||||
|
|
||||||
#pragma comment(lib, "d3d9.lib")
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
// D3DX
|
|
||||||
HINSTANCE hD3DXDll = NULL;
|
|
||||||
D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA = NULL;
|
|
||||||
D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA = NULL;
|
|
||||||
D3DXCOMPILESHADERTYPE PD3DXCompileShader = NULL;
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
LPDIRECT3D9 D3D = NULL; // Used to create the D3DDevice
|
|
||||||
LPDIRECT3DDEVICE9 dev = NULL; // Our rendering device
|
|
||||||
LPDIRECT3DSURFACE9 back_buffer;
|
|
||||||
LPDIRECT3DSURFACE9 back_buffer_z;
|
|
||||||
D3DCAPS9 caps;
|
|
||||||
HWND hWnd;
|
|
||||||
|
|
||||||
static int multisample;
|
|
||||||
static int resolution;
|
|
||||||
static int xres, yres;
|
|
||||||
static bool auto_depth_stencil = false;
|
|
||||||
|
|
||||||
#define VENDOR_NVIDIA 4318
|
|
||||||
#define VENDOR_ATI 4098
|
|
||||||
|
|
||||||
bool bFrameInProgress = false;
|
|
||||||
|
|
||||||
#define MAX_ADAPTERS 4
|
|
||||||
static Adapter adapters[MAX_ADAPTERS];
|
|
||||||
static int numAdapters;
|
|
||||||
static int cur_adapter;
|
|
||||||
|
|
||||||
// Value caches for state filtering
|
|
||||||
const int MaxTextureStages = 9;
|
|
||||||
const int MaxRenderStates = 210 + 46;
|
|
||||||
const int MaxTextureTypes = 33;
|
|
||||||
const int MaxSamplerSize = 13;
|
|
||||||
const int MaxSamplerTypes = 15;
|
|
||||||
static bool m_RenderStatesSet[MaxRenderStates];
|
|
||||||
static DWORD m_RenderStates[MaxRenderStates];
|
|
||||||
static bool m_RenderStatesChanged[MaxRenderStates];
|
|
||||||
|
|
||||||
static DWORD m_TextureStageStates[MaxTextureStages][MaxTextureTypes];
|
|
||||||
static bool m_TextureStageStatesSet[MaxTextureStages][MaxTextureTypes];
|
|
||||||
static bool m_TextureStageStatesChanged[MaxTextureStages][MaxTextureTypes];
|
|
||||||
|
|
||||||
static DWORD m_SamplerStates[MaxSamplerSize][MaxSamplerTypes];
|
|
||||||
static bool m_SamplerStatesSet[MaxSamplerSize][MaxSamplerTypes];
|
|
||||||
static bool m_SamplerStatesChanged[MaxSamplerSize][MaxSamplerTypes];
|
|
||||||
|
|
||||||
LPDIRECT3DBASETEXTURE9 m_Textures[16];
|
|
||||||
LPDIRECT3DVERTEXDECLARATION9 m_VtxDecl;
|
|
||||||
LPDIRECT3DPIXELSHADER9 m_PixelShader;
|
|
||||||
LPDIRECT3DVERTEXSHADER9 m_VertexShader;
|
|
||||||
|
|
||||||
void Enumerate();
|
|
||||||
|
|
||||||
int GetNumAdapters() { return numAdapters; }
|
|
||||||
const Adapter &GetAdapter(int i) { return adapters[i]; }
|
|
||||||
const Adapter &GetCurAdapter() { return adapters[cur_adapter]; }
|
|
||||||
|
|
||||||
bool IsATIDevice()
|
|
||||||
{
|
|
||||||
return GetCurAdapter().ident.VendorId == VENDOR_ATI;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HRESULT Init()
|
|
||||||
{
|
|
||||||
// Create the D3D object, which is needed to create the D3DDevice.
|
|
||||||
D3D = Direct3DCreate9(D3D_SDK_VERSION);
|
|
||||||
if (!D3D)
|
|
||||||
return E_FAIL;
|
|
||||||
Enumerate();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
D3D->Release();
|
|
||||||
D3D = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnableAlphaToCoverage()
|
|
||||||
{
|
|
||||||
// Each vendor has their own specific little hack.
|
|
||||||
if (GetCurAdapter().ident.VendorId == VENDOR_ATI)
|
|
||||||
D3D::SetRenderState(D3DRS_POINTSIZE, (D3DFORMAT)MAKEFOURCC('A', '2', 'M', '1'));
|
|
||||||
else
|
|
||||||
D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C'));
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp)
|
|
||||||
{
|
|
||||||
ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS));
|
|
||||||
pp->hDeviceWindow = hWnd;
|
|
||||||
|
|
||||||
if (auto_depth_stencil)
|
|
||||||
{
|
|
||||||
pp->EnableAutoDepthStencil = TRUE;
|
|
||||||
pp->AutoDepthStencilFormat = D3DFMT_D24S8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pp->EnableAutoDepthStencil = FALSE;
|
|
||||||
pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
pp->BackBufferFormat = D3DFMT_X8R8G8B8;
|
|
||||||
if (aa_mode >= (int)adapters[adapter].aa_levels.size())
|
|
||||||
aa_mode = 0;
|
|
||||||
|
|
||||||
pp->MultiSampleType = adapters[adapter].aa_levels[aa_mode].ms_setting;
|
|
||||||
pp->MultiSampleQuality = adapters[adapter].aa_levels[aa_mode].qual_setting;
|
|
||||||
|
|
||||||
pp->Flags = auto_depth_stencil ? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL : 0;
|
|
||||||
|
|
||||||
RECT client;
|
|
||||||
GetClientRect(hWnd, &client);
|
|
||||||
xres = pp->BackBufferWidth = client.right - client.left;
|
|
||||||
yres = pp->BackBufferHeight = client.bottom - client.top;
|
|
||||||
pp->SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
||||||
pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
||||||
pp->Windowed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Enumerate()
|
|
||||||
{
|
|
||||||
numAdapters = D3D::D3D->GetAdapterCount();
|
|
||||||
|
|
||||||
for (int i = 0; i < std::min(MAX_ADAPTERS, numAdapters); i++)
|
|
||||||
{
|
|
||||||
Adapter &a = adapters[i];
|
|
||||||
a.aa_levels.clear();
|
|
||||||
a.resolutions.clear();
|
|
||||||
D3D::D3D->GetAdapterIdentifier(i, 0, &a.ident);
|
|
||||||
bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA;
|
|
||||||
|
|
||||||
// Add SuperSamples modes
|
|
||||||
a.aa_levels.push_back(AALevel("None", D3DMULTISAMPLE_NONE, 0));
|
|
||||||
a.aa_levels.push_back(AALevel("4x SSAA", D3DMULTISAMPLE_NONE, 0));
|
|
||||||
a.aa_levels.push_back(AALevel("9x SSAA", D3DMULTISAMPLE_NONE, 0));
|
|
||||||
//Add multisample modes
|
|
||||||
//disable them will they are not implemnted
|
|
||||||
/*
|
|
||||||
DWORD qlevels = 0;
|
|
||||||
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels))
|
|
||||||
if (qlevels > 0)
|
|
||||||
a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0));
|
|
||||||
|
|
||||||
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels))
|
|
||||||
if (qlevels > 0)
|
|
||||||
a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0));
|
|
||||||
|
|
||||||
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels))
|
|
||||||
if (qlevels > 0)
|
|
||||||
a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0));
|
|
||||||
|
|
||||||
if (isNvidia)
|
|
||||||
{
|
|
||||||
// CSAA support
|
|
||||||
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels))
|
|
||||||
{
|
|
||||||
if (qlevels > 2)
|
|
||||||
{
|
|
||||||
// 8x, 8xQ are available
|
|
||||||
// See http://developer.nvidia.com/object/coverage-sampled-aa.html
|
|
||||||
a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2));
|
|
||||||
a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels))
|
|
||||||
{
|
|
||||||
if (qlevels > 2)
|
|
||||||
{
|
|
||||||
// 16x, 16xQ are available
|
|
||||||
// See http://developer.nvidia.com/object/coverage-sampled-aa.html
|
|
||||||
a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4));
|
|
||||||
a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Determine if INTZ is supported. Code from ATI's doc.
|
|
||||||
// http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf
|
|
||||||
a.supports_intz = D3D_OK == D3D->CheckDeviceFormat(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
|
|
||||||
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_INTZ);
|
|
||||||
// Also check for RAWZ (nvidia only, but the only option to get Z24 textures on sub GF8800
|
|
||||||
a.supports_rawz = D3D_OK == D3D->CheckDeviceFormat(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
|
|
||||||
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RAWZ);
|
|
||||||
// Might as well check for RESZ and NULL too.
|
|
||||||
a.supports_resz = D3D_OK == D3D->CheckDeviceFormat(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
|
|
||||||
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RESZ);
|
|
||||||
a.supports_null = D3D_OK == D3D->CheckDeviceFormat(
|
|
||||||
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
|
|
||||||
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_NULL);
|
|
||||||
|
|
||||||
if (a.aa_levels.size() == 1)
|
|
||||||
{
|
|
||||||
strcpy(a.aa_levels[0].name, "(Not supported on this device)");
|
|
||||||
}
|
|
||||||
int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8);
|
|
||||||
for (int m = 0; m < numModes; m++)
|
|
||||||
{
|
|
||||||
D3DDISPLAYMODE mode;
|
|
||||||
D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode);
|
|
||||||
|
|
||||||
int found = -1;
|
|
||||||
for (int x = 0; x < (int)a.resolutions.size(); x++)
|
|
||||||
{
|
|
||||||
if (a.resolutions[x].xres == mode.Width && a.resolutions[x].yres == mode.Height)
|
|
||||||
{
|
|
||||||
found = x;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Resolution temp;
|
|
||||||
Resolution &r = found==-1 ? temp : a.resolutions[found];
|
|
||||||
|
|
||||||
sprintf(r.name, "%ix%i", mode.Width, mode.Height);
|
|
||||||
r.bitdepths.insert(mode.Format);
|
|
||||||
r.refreshes.insert(mode.RefreshRate);
|
|
||||||
if (found == -1 && mode.Width >= 640 && mode.Height >= 480)
|
|
||||||
{
|
|
||||||
r.xres = mode.Width;
|
|
||||||
r.yres = mode.Height;
|
|
||||||
a.resolutions.push_back(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dynamically picks one of the available d3dx9 dlls and loads it.
|
|
||||||
// we're first trying to load the dll Dolphin was compiled with, otherwise the most up-to-date one
|
|
||||||
HRESULT LoadD3DX9()
|
|
||||||
{
|
|
||||||
HRESULT hr = E_FAIL;
|
|
||||||
hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str());
|
|
||||||
if (hD3DXDll != NULL)
|
|
||||||
{
|
|
||||||
NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str());
|
|
||||||
hr = S_OK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if that fails, try loading older dlls (no need to look for newer ones)
|
|
||||||
for (unsigned int num = D3DX_SDK_VERSION-1; num >= 24; --num)
|
|
||||||
{
|
|
||||||
hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", num).c_str());
|
|
||||||
if (hD3DXDll != NULL)
|
|
||||||
{
|
|
||||||
NOTICE_LOG(VIDEO, "Successfully loaded %s. If you're having trouble, try updating your DX runtime first.", StringFromFormat("d3dx9_%d.dll", num).c_str());
|
|
||||||
hr = S_OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
MessageBoxA(NULL, "Failed to load any D3DX9 dll, update your DX9 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PD3DXCompileShader = (D3DXCOMPILESHADERTYPE)GetProcAddress(hD3DXDll, "D3DXCompileShader");
|
|
||||||
if (PD3DXCompileShader == NULL)
|
|
||||||
{
|
|
||||||
MessageBoxA(NULL, "GetProcAddress failed for D3DXCompileShader!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
PD3DXSaveSurfaceToFileA = (D3DXSAVESURFACETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveSurfaceToFileA");
|
|
||||||
if (PD3DXSaveSurfaceToFileA == NULL)
|
|
||||||
{
|
|
||||||
MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveSurfaceToFileA!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
PD3DXSaveTextureToFileA = (D3DXSAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveTextureToFileA");
|
|
||||||
if (PD3DXSaveTextureToFileA == NULL)
|
|
||||||
{
|
|
||||||
MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
return S_OK;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
FreeLibrary(hD3DXDll);
|
|
||||||
PD3DXCompileShader = NULL;
|
|
||||||
PD3DXSaveSurfaceToFileA = NULL;
|
|
||||||
PD3DXSaveTextureToFileA = NULL;
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnloadD3DX9()
|
|
||||||
{
|
|
||||||
FreeLibrary(hD3DXDll);
|
|
||||||
PD3DXCompileShader = NULL;
|
|
||||||
PD3DXSaveSurfaceToFileA = NULL;
|
|
||||||
PD3DXSaveTextureToFileA = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT Create(int adapter, HWND wnd, int _resolution, int aa_mode, bool auto_depth)
|
|
||||||
{
|
|
||||||
hWnd = wnd;
|
|
||||||
multisample = aa_mode;
|
|
||||||
resolution = _resolution;
|
|
||||||
auto_depth_stencil = auto_depth;
|
|
||||||
cur_adapter = adapter;
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp;
|
|
||||||
|
|
||||||
HRESULT hr = LoadD3DX9();
|
|
||||||
if (FAILED(hr)) return hr;
|
|
||||||
|
|
||||||
InitPP(adapter, resolution, aa_mode, &d3dpp);
|
|
||||||
|
|
||||||
if (FAILED(D3D->CreateDevice(
|
|
||||||
adapter,
|
|
||||||
D3DDEVTYPE_HAL,
|
|
||||||
wnd,
|
|
||||||
D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, //doesn't seem to make a difference
|
|
||||||
&d3dpp, &dev)))
|
|
||||||
{
|
|
||||||
if (FAILED(D3D->CreateDevice(
|
|
||||||
adapter,
|
|
||||||
D3DDEVTYPE_HAL,
|
|
||||||
wnd,
|
|
||||||
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
|
|
||||||
&d3dpp, &dev)))
|
|
||||||
{
|
|
||||||
MessageBox(wnd,
|
|
||||||
_T("Failed to initialize Direct3D."),
|
|
||||||
_T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->GetDeviceCaps(&caps);
|
|
||||||
dev->GetRenderTarget(0, &back_buffer);
|
|
||||||
if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND)
|
|
||||||
back_buffer_z = NULL;
|
|
||||||
D3D::SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE );
|
|
||||||
D3D::SetRenderState(D3DRS_FILLMODE, g_Config.bWireFrame ? D3DFILL_WIREFRAME : D3DFILL_SOLID);
|
|
||||||
memset(m_Textures, 0, sizeof(m_Textures));
|
|
||||||
memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet));
|
|
||||||
memset(m_RenderStatesSet, 0, sizeof(m_RenderStatesSet));
|
|
||||||
memset(m_SamplerStatesSet, 0, sizeof(m_SamplerStatesSet));
|
|
||||||
memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged));
|
|
||||||
memset(m_RenderStatesChanged, 0, sizeof(m_RenderStatesChanged));
|
|
||||||
memset(m_SamplerStatesChanged, 0, sizeof(m_SamplerStatesChanged));
|
|
||||||
m_VtxDecl = NULL;
|
|
||||||
m_PixelShader = NULL;
|
|
||||||
m_VertexShader = NULL;
|
|
||||||
// Device state would normally be set here
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close()
|
|
||||||
{
|
|
||||||
UnloadD3DX9();
|
|
||||||
|
|
||||||
if (back_buffer_z)
|
|
||||||
back_buffer_z->Release();
|
|
||||||
back_buffer_z = NULL;
|
|
||||||
if( back_buffer )
|
|
||||||
back_buffer->Release();
|
|
||||||
back_buffer = NULL;
|
|
||||||
|
|
||||||
ULONG references = dev->Release();
|
|
||||||
if (references)
|
|
||||||
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
|
|
||||||
|
|
||||||
dev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const D3DCAPS9 &GetCaps()
|
|
||||||
{
|
|
||||||
return caps;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *VertexShaderVersionString()
|
|
||||||
{
|
|
||||||
static const char *versions[5] = {"ERROR", "vs_1_4", "vs_2_0", "vs_3_0", "vs_4_0"};
|
|
||||||
int version = ((D3D::caps.VertexShaderVersion >> 8) & 0xFF);
|
|
||||||
return versions[std::min(4, version)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *PixelShaderVersionString()
|
|
||||||
{
|
|
||||||
static const char *versions[5] = {"ERROR", "ps_1_4", "ps_2_0", "ps_3_0", "ps_4_0"};
|
|
||||||
int version = ((D3D::caps.PixelShaderVersion >> 8) & 0xFF);
|
|
||||||
return versions[std::min(4, version)];
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 GetBackBufferSurface()
|
|
||||||
{
|
|
||||||
return back_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 GetBackBufferDepthSurface()
|
|
||||||
{
|
|
||||||
return back_buffer_z;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShowD3DError(HRESULT err)
|
|
||||||
{
|
|
||||||
switch (err)
|
|
||||||
{
|
|
||||||
case D3DERR_DEVICELOST:
|
|
||||||
PanicAlert("Device Lost");
|
|
||||||
break;
|
|
||||||
case D3DERR_INVALIDCALL:
|
|
||||||
PanicAlert("Invalid Call");
|
|
||||||
break;
|
|
||||||
case D3DERR_DRIVERINTERNALERROR:
|
|
||||||
PanicAlert("Driver Internal Error");
|
|
||||||
break;
|
|
||||||
case D3DERR_OUTOFVIDEOMEMORY:
|
|
||||||
PanicAlert("Out of vid mem");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// MessageBox(0,_T("Other error or success"),_T("ERROR"),0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset()
|
|
||||||
{
|
|
||||||
if (dev)
|
|
||||||
{
|
|
||||||
// ForgetCachedState();
|
|
||||||
|
|
||||||
// Can't keep a pointer around to the backbuffer surface when resetting.
|
|
||||||
SAFE_RELEASE(back_buffer_z);
|
|
||||||
SAFE_RELEASE(back_buffer);
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp;
|
|
||||||
InitPP(cur_adapter, resolution, multisample, &d3dpp);
|
|
||||||
HRESULT hr = dev->Reset(&d3dpp);
|
|
||||||
ShowD3DError(hr);
|
|
||||||
|
|
||||||
dev->GetRenderTarget(0, &back_buffer);
|
|
||||||
if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND)
|
|
||||||
back_buffer_z = NULL;
|
|
||||||
ApplyCachedState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetBackBufferWidth()
|
|
||||||
{
|
|
||||||
return xres;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetBackBufferHeight()
|
|
||||||
{
|
|
||||||
return yres;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BeginFrame()
|
|
||||||
{
|
|
||||||
if (bFrameInProgress)
|
|
||||||
{
|
|
||||||
PanicAlert("BeginFrame WTF");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bFrameInProgress = true;
|
|
||||||
if (dev)
|
|
||||||
{
|
|
||||||
dev->BeginScene();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndFrame()
|
|
||||||
{
|
|
||||||
if (!bFrameInProgress)
|
|
||||||
{
|
|
||||||
PanicAlert("EndFrame WTF");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bFrameInProgress = false;
|
|
||||||
dev->EndScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Present()
|
|
||||||
{
|
|
||||||
if (dev)
|
|
||||||
{
|
|
||||||
dev->Present(NULL, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ApplyCachedState()
|
|
||||||
{
|
|
||||||
for (int sampler = 0; sampler < 8; sampler++)
|
|
||||||
{
|
|
||||||
for (int type = 0; type < MaxSamplerTypes; type++)
|
|
||||||
{
|
|
||||||
if(m_SamplerStatesSet[sampler][type])
|
|
||||||
D3D::dev->SetSamplerState(sampler, (D3DSAMPLERSTATETYPE)type, m_SamplerStates[sampler][type]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int rs = 0; rs < MaxRenderStates; rs++)
|
|
||||||
{
|
|
||||||
if (m_RenderStatesSet[rs])
|
|
||||||
D3D::dev->SetRenderState((D3DRENDERSTATETYPE)rs, m_RenderStates[rs]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't bother restoring these so let's just wipe the state copy
|
|
||||||
// so no stale state is around.
|
|
||||||
memset(m_Textures, 0, sizeof(m_Textures));
|
|
||||||
memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet));
|
|
||||||
memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged));
|
|
||||||
m_VtxDecl = NULL;
|
|
||||||
m_PixelShader = NULL;
|
|
||||||
m_VertexShader = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture)
|
|
||||||
{
|
|
||||||
if (m_Textures[Stage] != pTexture)
|
|
||||||
{
|
|
||||||
m_Textures[Stage] = pTexture;
|
|
||||||
D3D::dev->SetTexture(Stage, pTexture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshRenderState(D3DRENDERSTATETYPE State)
|
|
||||||
{
|
|
||||||
if(m_RenderStatesSet[State] && m_RenderStatesChanged[State])
|
|
||||||
{
|
|
||||||
D3D::dev->SetRenderState(State, m_RenderStates[State]);
|
|
||||||
m_RenderStatesChanged[State] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_RenderStates[State] != Value || !m_RenderStatesSet[State])
|
|
||||||
{
|
|
||||||
m_RenderStates[State] = Value;
|
|
||||||
m_RenderStatesSet[State] = true;
|
|
||||||
m_RenderStatesChanged[State] = false;
|
|
||||||
D3D::dev->SetRenderState(State, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_RenderStates[State] != Value || !m_RenderStatesSet[State])
|
|
||||||
{
|
|
||||||
m_RenderStatesChanged[State] = m_RenderStatesSet[State];
|
|
||||||
D3D::dev->SetRenderState(State, Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_RenderStatesChanged[State] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type])
|
|
||||||
{
|
|
||||||
m_TextureStageStates[Stage][Type] = Value;
|
|
||||||
m_TextureStageStatesSet[Stage][Type]=true;
|
|
||||||
m_TextureStageStatesChanged[Stage][Type]=false;
|
|
||||||
D3D::dev->SetTextureStageState(Stage, Type, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type)
|
|
||||||
{
|
|
||||||
if(m_TextureStageStatesSet[Stage][Type] && m_TextureStageStatesChanged[Stage][Type])
|
|
||||||
{
|
|
||||||
D3D::dev->SetTextureStageState(Stage, Type, m_TextureStageStates[Stage][Type]);
|
|
||||||
m_TextureStageStatesChanged[Stage][Type] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type])
|
|
||||||
{
|
|
||||||
m_TextureStageStatesChanged[Stage][Type] = m_TextureStageStatesSet[Stage][Type];
|
|
||||||
D3D::dev->SetTextureStageState(Stage, Type, Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_TextureStageStatesChanged[Stage][Type] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type])
|
|
||||||
{
|
|
||||||
m_SamplerStates[Sampler][Type] = Value;
|
|
||||||
m_SamplerStatesSet[Sampler][Type] = true;
|
|
||||||
m_SamplerStatesChanged[Sampler][Type] = false;
|
|
||||||
D3D::dev->SetSamplerState(Sampler, Type, Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type)
|
|
||||||
{
|
|
||||||
if(m_SamplerStatesSet[Sampler][Type] && m_SamplerStatesChanged[Sampler][Type])
|
|
||||||
{
|
|
||||||
D3D::dev->SetSamplerState(Sampler, Type, m_SamplerStates[Sampler][Type]);
|
|
||||||
m_SamplerStatesChanged[Sampler][Type] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
|
|
||||||
{
|
|
||||||
if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type])
|
|
||||||
{
|
|
||||||
m_SamplerStatesChanged[Sampler][Type] = m_SamplerStatesSet[Sampler][Type];
|
|
||||||
D3D::dev->SetSamplerState(Sampler, Type, Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_SamplerStatesChanged[Sampler][Type] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshVertexDeclaration()
|
|
||||||
{
|
|
||||||
if (m_VtxDecl)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexDeclaration(m_VtxDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl)
|
|
||||||
{
|
|
||||||
if (!decl) {
|
|
||||||
m_VtxDecl = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (decl != m_VtxDecl)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexDeclaration(decl);
|
|
||||||
m_VtxDecl = decl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshVertexShader()
|
|
||||||
{
|
|
||||||
if (m_VertexShader)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexShader(m_VertexShader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader)
|
|
||||||
{
|
|
||||||
if (!shader) {
|
|
||||||
m_VertexShader = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (shader != m_VertexShader)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexShader(shader);
|
|
||||||
m_VertexShader = shader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RefreshPixelShader()
|
|
||||||
{
|
|
||||||
if (m_PixelShader)
|
|
||||||
{
|
|
||||||
D3D::dev->SetPixelShader(m_PixelShader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader)
|
|
||||||
{
|
|
||||||
if (!shader) {
|
|
||||||
m_PixelShader = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (shader != m_PixelShader)
|
|
||||||
{
|
|
||||||
D3D::dev->SetPixelShader(shader);
|
|
||||||
m_PixelShader = shader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,165 +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 _D3DBASE_H
|
|
||||||
#define _D3DBASE_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <d3dx9.h>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; }
|
|
||||||
#define SAFE_DELETE(x) { delete (x); (x) = NULL; }
|
|
||||||
|
|
||||||
// From http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf
|
|
||||||
// Magic FourCC's to unlock undocumented D3D9 features:
|
|
||||||
|
|
||||||
// Z texture formats
|
|
||||||
#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z')))
|
|
||||||
#define FOURCC_RAWZ ((D3DFORMAT)(MAKEFOURCC('R','A','W','Z')))
|
|
||||||
#define FOURCC_DF24 ((D3DFORMAT)(MAKEFOURCC('D','F','2','4')))
|
|
||||||
#define FOURCC_DF16 ((D3DFORMAT)(MAKEFOURCC('D','F','1','6')))
|
|
||||||
|
|
||||||
// Depth buffer resolve:
|
|
||||||
#define FOURCC_RESZ ((D3DFORMAT)(MAKEFOURCC('R','E','S','Z')))
|
|
||||||
#define RESZ_CODE 0x7fa05000
|
|
||||||
|
|
||||||
// Null render target to do Z-only shadow maps: (probably not useful for Dolphin)
|
|
||||||
#define FOURCC_NULL ((D3DFORMAT)(MAKEFOURCC('N','U','L','L')))
|
|
||||||
|
|
||||||
bool IsATIDevice();
|
|
||||||
HRESULT Init();
|
|
||||||
HRESULT Create(int adapter, HWND wnd, int resolution, int aa_mode, bool auto_depth);
|
|
||||||
void Close();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
// Direct access to the device.
|
|
||||||
extern LPDIRECT3DDEVICE9 dev;
|
|
||||||
extern bool bFrameInProgress;
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
bool BeginFrame();
|
|
||||||
void EndFrame();
|
|
||||||
void Present();
|
|
||||||
bool CanUseINTZ();
|
|
||||||
|
|
||||||
int GetBackBufferWidth();
|
|
||||||
int GetBackBufferHeight();
|
|
||||||
LPDIRECT3DSURFACE9 GetBackBufferSurface();
|
|
||||||
LPDIRECT3DSURFACE9 GetBackBufferDepthSurface();
|
|
||||||
LPDIRECT3DVERTEXBUFFER9 GetquadVB();
|
|
||||||
LPDIRECT3DVERTEXDECLARATION9 GetBasicvertexDecl();
|
|
||||||
const D3DCAPS9 &GetCaps();
|
|
||||||
const char *PixelShaderVersionString();
|
|
||||||
const char *VertexShaderVersionString();
|
|
||||||
void ShowD3DError(HRESULT err);
|
|
||||||
|
|
||||||
// The following are "filtered" versions of the corresponding D3Ddev-> functions.
|
|
||||||
void SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture);
|
|
||||||
void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
|
|
||||||
void RefreshRenderState(D3DRENDERSTATETYPE State);
|
|
||||||
void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value);
|
|
||||||
|
|
||||||
void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
|
|
||||||
void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type);
|
|
||||||
void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
|
|
||||||
|
|
||||||
void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
|
|
||||||
void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type);
|
|
||||||
void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
|
|
||||||
|
|
||||||
void RefreshVertexDeclaration();
|
|
||||||
void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl);
|
|
||||||
|
|
||||||
void RefreshVertexShader();
|
|
||||||
void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader);
|
|
||||||
|
|
||||||
void RefreshPixelShader();
|
|
||||||
void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader);
|
|
||||||
|
|
||||||
void ApplyCachedState();
|
|
||||||
|
|
||||||
// Utility functions for vendor specific hacks. So far, just the one.
|
|
||||||
void EnableAlphaToCoverage();
|
|
||||||
|
|
||||||
struct Resolution
|
|
||||||
{
|
|
||||||
char name[32];
|
|
||||||
int xres;
|
|
||||||
int yres;
|
|
||||||
std::set<D3DFORMAT> bitdepths;
|
|
||||||
std::set<int> refreshes;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AALevel
|
|
||||||
{
|
|
||||||
AALevel(const char *n, D3DMULTISAMPLE_TYPE m, int q) {
|
|
||||||
strncpy(name, n, 32);
|
|
||||||
name[31] = '\0';
|
|
||||||
ms_setting = m;
|
|
||||||
qual_setting = q;
|
|
||||||
}
|
|
||||||
char name[32];
|
|
||||||
D3DMULTISAMPLE_TYPE ms_setting;
|
|
||||||
int qual_setting;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Adapter
|
|
||||||
{
|
|
||||||
D3DADAPTER_IDENTIFIER9 ident;
|
|
||||||
std::vector<Resolution> resolutions;
|
|
||||||
std::vector<AALevel> aa_levels;
|
|
||||||
bool supports_alpha_to_coverage;
|
|
||||||
|
|
||||||
// Magic render targets, see the top of this file.
|
|
||||||
bool supports_intz;
|
|
||||||
bool supports_rawz;
|
|
||||||
bool supports_resz;
|
|
||||||
bool supports_null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Adapter &GetAdapter(int i);
|
|
||||||
const Adapter &GetCurAdapter();
|
|
||||||
int GetNumAdapters();
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
|
|
||||||
// Used to not require the SDK and runtime versions to match:
|
|
||||||
// Linking with d3dx9.lib makes the most recent d3dx9_xx.dll of the
|
|
||||||
// compiler's SDK an actually unnecessary requirement.
|
|
||||||
// Add any d3dx9 functions which you want to use here and load them in LoadD3DX9()
|
|
||||||
typedef HRESULT (WINAPI* D3DXSAVESURFACETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DSURFACE9, CONST PALETTEENTRY*, CONST RECT*);
|
|
||||||
typedef HRESULT (WINAPI* D3DXSAVETEXTURETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DBASETEXTURE9, CONST PALETTEENTRY*);
|
|
||||||
typedef HRESULT (WINAPI* D3DXCOMPILESHADERTYPE)(LPCSTR, UINT, CONST D3DXMACRO*, LPD3DXINCLUDE, LPCSTR, LPCSTR, DWORD, LPD3DXBUFFER*, LPD3DXBUFFER*, LPD3DXCONSTANTTABLE*);
|
|
||||||
|
|
||||||
extern D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA;
|
|
||||||
extern D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA;
|
|
||||||
extern D3DXCOMPILESHADERTYPE PD3DXCompileShader;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,150 +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 <d3dx9.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "DX9_D3DShader.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
// Bytecode->shader.
|
|
||||||
LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len)
|
|
||||||
{
|
|
||||||
LPDIRECT3DVERTEXSHADER9 v_shader;
|
|
||||||
HRESULT hr = D3D::dev->CreateVertexShader((DWORD *)bytecode, &v_shader);
|
|
||||||
if (FAILED(hr))
|
|
||||||
v_shader = 0;
|
|
||||||
return v_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Code->bytecode.
|
|
||||||
bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen)
|
|
||||||
{
|
|
||||||
//try to compile
|
|
||||||
LPD3DXBUFFER shaderBuffer = 0;
|
|
||||||
LPD3DXBUFFER errorBuffer = 0;
|
|
||||||
HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::VertexShaderVersionString(),
|
|
||||||
0, &shaderBuffer, &errorBuffer, 0);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
//compilation error
|
|
||||||
if (g_ActiveConfig.bShowShaderErrors) {
|
|
||||||
std::string hello = (char*)errorBuffer->GetBufferPointer();
|
|
||||||
hello += "\n\n";
|
|
||||||
hello += code;
|
|
||||||
MessageBoxA(0, hello.c_str(), "Error compiling vertex shader", MB_ICONERROR);
|
|
||||||
}
|
|
||||||
*bytecode = 0;
|
|
||||||
*bytecodelen = 0;
|
|
||||||
}
|
|
||||||
else if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
*bytecodelen = shaderBuffer->GetBufferSize();
|
|
||||||
*bytecode = new u8[*bytecodelen];
|
|
||||||
memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
if (shaderBuffer)
|
|
||||||
shaderBuffer->Release();
|
|
||||||
if (errorBuffer)
|
|
||||||
errorBuffer->Release();
|
|
||||||
return SUCCEEDED(hr) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Bytecode->shader.
|
|
||||||
LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len)
|
|
||||||
{
|
|
||||||
LPDIRECT3DPIXELSHADER9 p_shader;
|
|
||||||
HRESULT hr = D3D::dev->CreatePixelShader((DWORD *)bytecode, &p_shader);
|
|
||||||
if (FAILED(hr))
|
|
||||||
p_shader = 0;
|
|
||||||
return p_shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen)
|
|
||||||
{
|
|
||||||
LPD3DXBUFFER shaderBuffer = 0;
|
|
||||||
LPD3DXBUFFER errorBuffer = 0;
|
|
||||||
|
|
||||||
// Someone:
|
|
||||||
// For some reason, I had this kind of errors : "Shader uses texture addressing operations
|
|
||||||
// in a dependency chain that is too complex for the target shader model (ps_2_0) to handle."
|
|
||||||
HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::PixelShaderVersionString(),
|
|
||||||
0, &shaderBuffer, &errorBuffer, 0);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
if (g_ActiveConfig.bShowShaderErrors) {
|
|
||||||
std::string hello = (char*)errorBuffer->GetBufferPointer();
|
|
||||||
hello += "\n\n";
|
|
||||||
hello += code;
|
|
||||||
MessageBoxA(0, hello.c_str(), "Error compiling pixel shader", MB_ICONERROR);
|
|
||||||
}
|
|
||||||
*bytecode = 0;
|
|
||||||
*bytecodelen = 0;
|
|
||||||
}
|
|
||||||
else if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
*bytecodelen = shaderBuffer->GetBufferSize();
|
|
||||||
*bytecode = new u8[*bytecodelen];
|
|
||||||
memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen);
|
|
||||||
}
|
|
||||||
|
|
||||||
//cleanup
|
|
||||||
if (shaderBuffer)
|
|
||||||
shaderBuffer->Release();
|
|
||||||
if (errorBuffer)
|
|
||||||
errorBuffer->Release();
|
|
||||||
return SUCCEEDED(hr) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len) {
|
|
||||||
u8 *bytecode;
|
|
||||||
int bytecodelen;
|
|
||||||
if (CompileVertexShader(code, len, &bytecode, &bytecodelen)) {
|
|
||||||
LPDIRECT3DVERTEXSHADER9 v_shader = CreateVertexShaderFromByteCode(bytecode, len);
|
|
||||||
delete [] bytecode;
|
|
||||||
return v_shader;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len) {
|
|
||||||
u8 *bytecode;
|
|
||||||
int bytecodelen;
|
|
||||||
if (CompilePixelShader(code, len, &bytecode, &bytecodelen)) {
|
|
||||||
LPDIRECT3DPIXELSHADER9 p_shader = CreatePixelShaderFromByteCode(bytecode, len);
|
|
||||||
delete [] bytecode;
|
|
||||||
return p_shader;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len);
|
|
||||||
LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len);
|
|
||||||
|
|
||||||
// The returned bytecode buffers should be delete[]-d.
|
|
||||||
bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen);
|
|
||||||
bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen);
|
|
||||||
|
|
||||||
// Utility functions
|
|
||||||
LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len);
|
|
||||||
LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,275 +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 "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DTexture.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int levels)
|
|
||||||
{
|
|
||||||
u32* pBuffer = (u32*)buffer;
|
|
||||||
LPDIRECT3DTEXTURE9 pTexture;
|
|
||||||
|
|
||||||
// crazy bitmagic, sorry :)
|
|
||||||
bool isPow2 = !((width&(width-1)) || (height&(height-1)));
|
|
||||||
bool bExpand = false;
|
|
||||||
|
|
||||||
if (fmt == D3DFMT_A8P8) {
|
|
||||||
fmt = D3DFMT_A8L8;
|
|
||||||
bExpand = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
// TODO(ector): Allow mipmaps for non-pow textures on newer cards?
|
|
||||||
// TODO(ector): Use the game-specified mipmaps?
|
|
||||||
if (levels > 0)
|
|
||||||
hr = dev->CreateTexture(width, height, levels, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL);
|
|
||||||
else
|
|
||||||
hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
return 0;
|
|
||||||
int level = 0;
|
|
||||||
D3DLOCKED_RECT Lock;
|
|
||||||
pTexture->LockRect(level, &Lock, NULL, 0);
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case D3DFMT_L8:
|
|
||||||
case D3DFMT_A8:
|
|
||||||
case D3DFMT_A4L4:
|
|
||||||
{
|
|
||||||
const u8 *pIn = buffer;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_R5G6B5:
|
|
||||||
{
|
|
||||||
const u16 *pIn = (u16*)buffer;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 2);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_A8L8:
|
|
||||||
{
|
|
||||||
if (bExpand) { // I8
|
|
||||||
const u8 *pIn = buffer;
|
|
||||||
// TODO(XK): Find a better way that does not involve either unpacking
|
|
||||||
// or downsampling (i.e. A4L4)
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
for(int i = 0; i < width * 2; i += 2) {
|
|
||||||
pBits[i] = pIn[i / 2];
|
|
||||||
pBits[i + 1] = pIn[i / 2];
|
|
||||||
}
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
} else { // IA8
|
|
||||||
const u16 *pIn = (u16*)buffer;
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 2);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_A8R8G8B8:
|
|
||||||
{
|
|
||||||
if(pitch * 4 == Lock.Pitch && !swap_r_b)
|
|
||||||
{
|
|
||||||
memcpy(Lock.pBits,buffer,Lock.Pitch*height);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32* pIn = pBuffer;
|
|
||||||
if (!swap_r_b) {
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 4);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8 *pIn8 = (u8 *)pIn;
|
|
||||||
u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
for (int x = 0; x < width * 4; x += 4) {
|
|
||||||
pBits[x + 0] = pIn8[x + 2];
|
|
||||||
pBits[x + 1] = pIn8[x + 1];
|
|
||||||
pBits[x + 2] = pIn8[x + 0];
|
|
||||||
pBits[x + 3] = pIn8[x + 3];
|
|
||||||
}
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_DXT1:
|
|
||||||
memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PanicAlert("D3D: Invalid texture format %i", fmt);
|
|
||||||
}
|
|
||||||
pTexture->UnlockRect(level);
|
|
||||||
return pTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt)
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 pTexture;
|
|
||||||
// crazy bitmagic, sorry :)
|
|
||||||
bool isPow2 = !((width&(width-1)) || (height&(height-1)));
|
|
||||||
bool bExpand = false;
|
|
||||||
HRESULT hr;
|
|
||||||
// TODO(ector): Allow mipmaps for non-pow textures on newer cards?
|
|
||||||
// TODO(ector): Use the game-specified mipmaps?
|
|
||||||
if (!isPow2)
|
|
||||||
hr = dev->CreateTexture(width, height, 1, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL);
|
|
||||||
else
|
|
||||||
hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
return 0;
|
|
||||||
return pTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level)
|
|
||||||
{
|
|
||||||
u32* pBuffer = (u32*)buffer;
|
|
||||||
D3DLOCKED_RECT Lock;
|
|
||||||
pTexture->LockRect(level, &Lock, NULL, 0);
|
|
||||||
u32* pIn = pBuffer;
|
|
||||||
|
|
||||||
bool bExpand = false;
|
|
||||||
|
|
||||||
if (fmt == D3DFMT_A8P8) {
|
|
||||||
fmt = D3DFMT_A8L8;
|
|
||||||
bExpand = true;
|
|
||||||
}
|
|
||||||
switch (fmt)
|
|
||||||
{
|
|
||||||
case D3DFMT_A8R8G8B8:
|
|
||||||
if(pitch * 4 == Lock.Pitch && !swap_r_b)
|
|
||||||
{
|
|
||||||
memcpy(Lock.pBits, pBuffer, Lock.Pitch*height);
|
|
||||||
}
|
|
||||||
else if (!swap_r_b)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 4);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8 *pIn8 = (u8 *)pIn;
|
|
||||||
u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
for (int x = 0; x < width * 4; x += 4)
|
|
||||||
{
|
|
||||||
pBits[x + 0] = pIn8[x + 2];
|
|
||||||
pBits[x + 1] = pIn8[x + 1];
|
|
||||||
pBits[x + 2] = pIn8[x + 0];
|
|
||||||
pBits[x + 3] = pIn8[x + 3];
|
|
||||||
}
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_L8:
|
|
||||||
case D3DFMT_A8:
|
|
||||||
case D3DFMT_A4L4:
|
|
||||||
{
|
|
||||||
const u8 *pIn = buffer;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_R5G6B5:
|
|
||||||
{
|
|
||||||
const u16 *pIn = (u16*)buffer;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 2);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_A8L8:
|
|
||||||
{
|
|
||||||
if (bExpand) { // I8
|
|
||||||
const u8 *pIn = buffer;
|
|
||||||
// TODO(XK): Find a better way that does not involve either unpacking
|
|
||||||
// or downsampling (i.e. A4L4)
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
for(int i = 0; i < width * 2; i += 2) {
|
|
||||||
pBits[i] = pIn[i / 2];
|
|
||||||
pBits[i + 1] = pIn[i / 2];
|
|
||||||
}
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
} else { // IA8
|
|
||||||
const u16 *pIn = (u16*)buffer;
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch));
|
|
||||||
memcpy(pBits, pIn, width * 2);
|
|
||||||
pIn += pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D3DFMT_DXT1:
|
|
||||||
memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pTexture->UnlockRect(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,34 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt = D3DFMT_A8R8G8B8, bool swap_r_b = false, int levels = 1);
|
|
||||||
void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level = 0);
|
|
||||||
LPDIRECT3DTEXTURE9 CreateRenderTarget(const int width, const int height);
|
|
||||||
LPDIRECT3DSURFACE9 CreateDepthStencilSurface(const int width, const int height);
|
|
||||||
LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,447 +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 "Common.h"
|
|
||||||
#include "StringUtil.h"
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DUtil.h"
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
|
|
||||||
CD3DFont font;
|
|
||||||
|
|
||||||
#define MAX_NUM_VERTICES 50*6
|
|
||||||
struct FONT2DVERTEX {
|
|
||||||
float x,y,z;
|
|
||||||
float rhw;
|
|
||||||
u32 color;
|
|
||||||
float tu, tv;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
|
||||||
#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX1)
|
|
||||||
|
|
||||||
inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv)
|
|
||||||
{
|
|
||||||
FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
CD3DFont::CD3DFont()
|
|
||||||
{
|
|
||||||
m_pTexture = NULL;
|
|
||||||
m_pVB = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {m_dwTexWidth = 512, m_dwTexHeight = 512};
|
|
||||||
|
|
||||||
int CD3DFont::Init()
|
|
||||||
{
|
|
||||||
// Create vertex buffer for the letters
|
|
||||||
HRESULT hr;
|
|
||||||
if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX),
|
|
||||||
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL)))
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
m_fTextScale = 1.0f; // Draw fonts into texture without scaling
|
|
||||||
|
|
||||||
// Prepare to create a bitmap
|
|
||||||
int *pBitmapBits;
|
|
||||||
BITMAPINFO bmi;
|
|
||||||
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
|
|
||||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
||||||
bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
|
|
||||||
bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
bmi.bmiHeader.biBitCount = 32;
|
|
||||||
|
|
||||||
// Create a DC and a bitmap for the font
|
|
||||||
HDC hDC = CreateCompatibleDC(NULL);
|
|
||||||
HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0);
|
|
||||||
SetMapMode(hDC, MM_TEXT);
|
|
||||||
|
|
||||||
// Create a font. By specifying ANTIALIASED_QUALITY, we might get an
|
|
||||||
// antialiased font, but this is not guaranteed.
|
|
||||||
// We definitely don't want to get it cleartype'd, anyway.
|
|
||||||
int m_dwFontHeight = 24;
|
|
||||||
int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72);
|
|
||||||
int dwBold = FW_NORMAL; ///FW_BOLD
|
|
||||||
HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0,
|
|
||||||
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
|
|
||||||
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
|
|
||||||
VARIABLE_PITCH, _T("Tahoma"));
|
|
||||||
if (NULL == hFont)
|
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
|
|
||||||
HGDIOBJ hOldFont = SelectObject(hDC, hFont);
|
|
||||||
|
|
||||||
// Set text properties
|
|
||||||
SetTextColor(hDC, 0xFFFFFF);
|
|
||||||
SetBkColor (hDC, 0);
|
|
||||||
SetTextAlign(hDC, TA_TOP);
|
|
||||||
|
|
||||||
// Loop through all printable character and output them to the bitmap..
|
|
||||||
// Meanwhile, keep track of the corresponding tex coords for each character.
|
|
||||||
int x = 0, y = 0;
|
|
||||||
char str[2] = "\0";
|
|
||||||
for (int c = 0; c < 127 - 32; c++)
|
|
||||||
{
|
|
||||||
str[0] = c + 32;
|
|
||||||
SIZE size;
|
|
||||||
GetTextExtentPoint32A(hDC, str, 1, &size);
|
|
||||||
if ((int)(x+size.cx+1) > m_dwTexWidth)
|
|
||||||
{
|
|
||||||
x = 0;
|
|
||||||
y += size.cy + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL);
|
|
||||||
m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth;
|
|
||||||
m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight;
|
|
||||||
m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
|
|
||||||
m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
|
|
||||||
|
|
||||||
x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new texture for the font
|
|
||||||
hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC,
|
|
||||||
D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create font texture");
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock the surface and write the alpha values for the set pixels
|
|
||||||
D3DLOCKED_RECT d3dlr;
|
|
||||||
m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD);
|
|
||||||
int bAlpha; // 4-bit measure of pixel intensity
|
|
||||||
|
|
||||||
for (y = 0; y < m_dwTexHeight; y++)
|
|
||||||
{
|
|
||||||
u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch);
|
|
||||||
for (x = 0; x < m_dwTexWidth; x++)
|
|
||||||
{
|
|
||||||
bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4);
|
|
||||||
pDst16[x] = (bAlpha << 12) | 0x0fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done updating texture, so clean up used objects
|
|
||||||
m_pTexture->UnlockRect(0);
|
|
||||||
|
|
||||||
SelectObject(hDC, hOldbmBitmap);
|
|
||||||
DeleteObject(hbmBitmap);
|
|
||||||
|
|
||||||
SelectObject(hDC, hOldFont);
|
|
||||||
DeleteObject(hFont);
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CD3DFont::Shutdown()
|
|
||||||
{
|
|
||||||
m_pVB->Release();
|
|
||||||
m_pVB = NULL;
|
|
||||||
m_pTexture->Release();
|
|
||||||
m_pTexture = NULL;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const int RS[6][2] =
|
|
||||||
{
|
|
||||||
{D3DRS_ALPHABLENDENABLE, TRUE},
|
|
||||||
{D3DRS_SRCBLEND, D3DBLEND_SRCALPHA},
|
|
||||||
{D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA},
|
|
||||||
{D3DRS_CULLMODE, D3DCULL_NONE},
|
|
||||||
{D3DRS_ZENABLE, FALSE},
|
|
||||||
{D3DRS_FOGENABLE, FALSE},
|
|
||||||
};
|
|
||||||
const int TS[6][2] =
|
|
||||||
{
|
|
||||||
{D3DTSS_COLOROP, D3DTOP_MODULATE},
|
|
||||||
{D3DTSS_COLORARG1, D3DTA_TEXTURE},
|
|
||||||
{D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
|
||||||
{D3DTSS_ALPHAOP, D3DTOP_MODULATE },
|
|
||||||
{D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
|
||||||
{D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
|
||||||
};
|
|
||||||
|
|
||||||
static LPDIRECT3DPIXELSHADER9 ps_old = NULL;
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 vs_old = NULL;
|
|
||||||
|
|
||||||
void RestoreShaders()
|
|
||||||
{
|
|
||||||
D3D::SetTexture(0, 0);
|
|
||||||
D3D::RefreshVertexDeclaration();
|
|
||||||
D3D::RefreshPixelShader();
|
|
||||||
D3D::RefreshVertexShader();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestoreRenderStates()
|
|
||||||
{
|
|
||||||
RestoreShaders();
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
D3D::RefreshRenderState((_D3DRENDERSTATETYPE)RS[i][0]);
|
|
||||||
D3D::RefreshTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CD3DFont::SetRenderStates()
|
|
||||||
{
|
|
||||||
D3D::SetTexture(0, m_pTexture);
|
|
||||||
|
|
||||||
dev->SetPixelShader(0);
|
|
||||||
dev->SetVertexShader(0);
|
|
||||||
|
|
||||||
dev->SetFVF(D3DFVF_FONT2DVERTEX);
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
D3D::ChangeRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]);
|
|
||||||
D3D::ChangeTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center)
|
|
||||||
{
|
|
||||||
if (!m_pVB)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
SetRenderStates();
|
|
||||||
dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX));
|
|
||||||
|
|
||||||
float vpWidth = 1;
|
|
||||||
float vpHeight = 1;
|
|
||||||
|
|
||||||
float sx = x*vpWidth-0.5f;
|
|
||||||
float sy = y*vpHeight-0.5f;
|
|
||||||
|
|
||||||
float fStartX = sx;
|
|
||||||
|
|
||||||
float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight);
|
|
||||||
// Fill vertex buffer
|
|
||||||
FONT2DVERTEX* pVertices;
|
|
||||||
int dwNumTriangles = 0L;
|
|
||||||
m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
|
|
||||||
|
|
||||||
const char *oldstrText=strText;
|
|
||||||
//First, let's measure the text
|
|
||||||
float tw=0;
|
|
||||||
float mx=0;
|
|
||||||
float maxx=0;
|
|
||||||
|
|
||||||
while (*strText)
|
|
||||||
{
|
|
||||||
char c = *strText++;
|
|
||||||
|
|
||||||
if (c == ('\n'))
|
|
||||||
mx = 0;
|
|
||||||
if (c < (' '))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float tx1 = m_fTexCoords[c-32][0];
|
|
||||||
float tx2 = m_fTexCoords[c-32][2];
|
|
||||||
|
|
||||||
float w = (tx2-tx1)*m_dwTexWidth;
|
|
||||||
w *= (fXScale*vpHeight)*invLineHeight;
|
|
||||||
mx += w + spacing*fXScale*vpWidth;
|
|
||||||
if (mx > maxx) maxx = mx;
|
|
||||||
}
|
|
||||||
|
|
||||||
float offset = -maxx/2;
|
|
||||||
strText = oldstrText;
|
|
||||||
//Then let's draw it
|
|
||||||
if (center)
|
|
||||||
{
|
|
||||||
sx+=offset;
|
|
||||||
fStartX+=offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
float wScale = (fXScale*vpHeight)*invLineHeight;
|
|
||||||
float hScale = (fYScale*vpHeight)*invLineHeight;
|
|
||||||
|
|
||||||
while (*strText)
|
|
||||||
{
|
|
||||||
char c = *strText++;
|
|
||||||
|
|
||||||
if (c == ('\n'))
|
|
||||||
{
|
|
||||||
sx = fStartX;
|
|
||||||
sy += fYScale*vpHeight;
|
|
||||||
}
|
|
||||||
if (c < (' '))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
c-=32;
|
|
||||||
float tx1 = m_fTexCoords[c][0];
|
|
||||||
float ty1 = m_fTexCoords[c][1];
|
|
||||||
float tx2 = m_fTexCoords[c][2];
|
|
||||||
float ty2 = m_fTexCoords[c][3];
|
|
||||||
|
|
||||||
float w = (tx2-tx1)*m_dwTexWidth;
|
|
||||||
float h = (ty2-ty1)*m_dwTexHeight;
|
|
||||||
|
|
||||||
w *= wScale;
|
|
||||||
h *= hScale;
|
|
||||||
|
|
||||||
FONT2DVERTEX v[6];
|
|
||||||
v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2);
|
|
||||||
v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1);
|
|
||||||
v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2);
|
|
||||||
v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1);
|
|
||||||
v[4] = v[2];
|
|
||||||
v[5] = v[1];
|
|
||||||
|
|
||||||
memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX));
|
|
||||||
|
|
||||||
pVertices+=6;
|
|
||||||
dwNumTriangles += 2;
|
|
||||||
|
|
||||||
if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
|
|
||||||
{
|
|
||||||
// Unlock, render, and relock the vertex buffer
|
|
||||||
m_pVB->Unlock();
|
|
||||||
dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
|
|
||||||
m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
|
|
||||||
dwNumTriangles = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sx += w + spacing*fXScale*vpWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock and render the vertex buffer
|
|
||||||
m_pVB->Unlock();
|
|
||||||
if (dwNumTriangles > 0)
|
|
||||||
dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
|
|
||||||
RestoreRenderStates();
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2)
|
|
||||||
{
|
|
||||||
struct Q2DVertex { float x,y,z,rhw;u32 color;float u,v,w,h; } coords[4] = {
|
|
||||||
{x1-0.5f, y1-0.5f, 0, 1, color, u1, v1},
|
|
||||||
{x2-0.5f, y1-0.5f, 0, 1, color, u2, v1},
|
|
||||||
{x2-0.5f, y2-0.5f, 0, 1, color, u2, v2},
|
|
||||||
{x1-0.5f, y2-0.5f, 0, 1, color, u1, v2},
|
|
||||||
};
|
|
||||||
dev->SetPixelShader(0);
|
|
||||||
dev->SetVertexShader(0);
|
|
||||||
dev->SetVertexDeclaration(NULL);
|
|
||||||
dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
|
|
||||||
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex));
|
|
||||||
RestoreShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawShadedTexQuad(IDirect3DTexture9 *texture,
|
|
||||||
const RECT *rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
int DestWidth,
|
|
||||||
int DestHeight,
|
|
||||||
IDirect3DPixelShader9 *PShader,
|
|
||||||
IDirect3DVertexShader9 *Vshader)
|
|
||||||
{
|
|
||||||
float sw = 1.0f /(float) SourceWidth;
|
|
||||||
float sh = 1.0f /(float) SourceHeight;
|
|
||||||
float dw = 1.0f /(float) DestWidth;
|
|
||||||
float dh = 1.0f /(float) DestHeight;
|
|
||||||
float u1=((float)rSource->left) * sw;
|
|
||||||
float u2=((float)rSource->right) * sw;
|
|
||||||
float v1=((float)rSource->top) * sh;
|
|
||||||
float v2=((float)rSource->bottom) * sh;
|
|
||||||
|
|
||||||
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = {
|
|
||||||
{-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2},
|
|
||||||
{-1.0f - dw, 1.0f + dh, 0.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2},
|
|
||||||
{ 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2},
|
|
||||||
{ 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2}
|
|
||||||
};
|
|
||||||
dev->SetVertexShader(Vshader);
|
|
||||||
dev->SetPixelShader(PShader);
|
|
||||||
D3D::SetTexture(0, texture);
|
|
||||||
dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2));
|
|
||||||
dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
|
|
||||||
RestoreShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
|
|
||||||
const MathUtil::Rectangle<float> *rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
const MathUtil::Rectangle<float> *rDest,
|
|
||||||
int DestWidth,
|
|
||||||
int DestHeight,
|
|
||||||
IDirect3DPixelShader9 *PShader,
|
|
||||||
IDirect3DVertexShader9 *Vshader)
|
|
||||||
{
|
|
||||||
float sw = 1.0f /(float) SourceWidth;
|
|
||||||
float sh = 1.0f /(float) SourceHeight;
|
|
||||||
float dw = 1.0f /(float) DestWidth;
|
|
||||||
float dh = 1.0f /(float) DestHeight;
|
|
||||||
float u1= rSource->left * sw;
|
|
||||||
float u2= rSource->right * sw;
|
|
||||||
float v1= rSource->top * sh;
|
|
||||||
float v2= rSource->bottom * sh;
|
|
||||||
|
|
||||||
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = {
|
|
||||||
{ rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2},
|
|
||||||
{ rDest->left - dw , rDest->bottom + dh, 1.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2},
|
|
||||||
{ rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2},
|
|
||||||
{ rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2}
|
|
||||||
};
|
|
||||||
dev->SetVertexShader(Vshader);
|
|
||||||
dev->SetPixelShader(PShader);
|
|
||||||
D3D::SetTexture(0, texture);
|
|
||||||
dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2));
|
|
||||||
dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
|
|
||||||
RestoreShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader)
|
|
||||||
{
|
|
||||||
struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = {
|
|
||||||
{-1.0f, 1.0f, z, 1.0f, Color},
|
|
||||||
{ 1.0f, 1.0f, z, 1.0f, Color},
|
|
||||||
{ 1.0f, -1.0f, z, 1.0f, Color},
|
|
||||||
{-1.0f, -1.0f, z, 1.0f, Color}
|
|
||||||
};
|
|
||||||
dev->SetVertexShader(Vshader);
|
|
||||||
dev->SetPixelShader(PShader);
|
|
||||||
dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE);
|
|
||||||
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex));
|
|
||||||
RestoreShaders();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,88 +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/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include <math.h>
|
|
||||||
#include <MathUtil.h>
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace D3D
|
|
||||||
{
|
|
||||||
// Font creation flags
|
|
||||||
#define D3DFONT_BOLD 0x0001
|
|
||||||
#define D3DFONT_ITALIC 0x0002
|
|
||||||
|
|
||||||
// Font rendering flags
|
|
||||||
#define D3DFONT_CENTERED 0x0001
|
|
||||||
|
|
||||||
//a cut-down variant of the DXSDK CD3DFont class
|
|
||||||
class CD3DFont
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font
|
|
||||||
LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text
|
|
||||||
//int m_dwTexWidth; // Texture dimensions
|
|
||||||
//int m_dwTexHeight;
|
|
||||||
float m_fTextScale;
|
|
||||||
float m_fTexCoords[128-32][4];
|
|
||||||
|
|
||||||
public:
|
|
||||||
CD3DFont();
|
|
||||||
// 2D (no longer 3D) text drawing function
|
|
||||||
// Initializing and destroying device-dependent objects
|
|
||||||
void SetRenderStates();
|
|
||||||
int Init();
|
|
||||||
int Shutdown();
|
|
||||||
int DrawTextScaled( float x, float y,
|
|
||||||
float fXScale, float fYScale,
|
|
||||||
float spacing, u32 dwColor,
|
|
||||||
const char* strText, bool center=true );
|
|
||||||
|
|
||||||
|
|
||||||
// Constructor / destructor
|
|
||||||
//~CD3DFont();
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CD3DFont font;
|
|
||||||
|
|
||||||
void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1=0, float v1=0, float u2=1, float v2=1);
|
|
||||||
void drawShadedTexQuad(IDirect3DTexture9 *texture,
|
|
||||||
const RECT *rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
int DestWidth,
|
|
||||||
int DestHeight,
|
|
||||||
IDirect3DPixelShader9 *PShader,
|
|
||||||
IDirect3DVertexShader9 *Vshader);
|
|
||||||
void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
|
|
||||||
const MathUtil::Rectangle<float> *rSource,
|
|
||||||
int SourceWidth,
|
|
||||||
int SourceHeight,
|
|
||||||
const MathUtil::Rectangle<float> *rDest,
|
|
||||||
int DestWidth,
|
|
||||||
int DestHeight,
|
|
||||||
IDirect3DPixelShader9 *PShader,
|
|
||||||
IDirect3DVertexShader9 *Vshader);
|
|
||||||
void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader);
|
|
||||||
void SaveRenderStates();
|
|
||||||
void RestoreRenderStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,285 +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 "DX9_D3DBase.h"
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
#include "DX9_FramebufferManager.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "DX9_TextureConverter.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
#undef CHECK
|
|
||||||
#define CHECK(hr, Message, ...) if (FAILED(hr)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
XFBSource FramebufferManager::m_realXFBSource;
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_color_texture;
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_colorRead_texture;
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depth_texture;
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depthRead_texture;
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_surface;
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_surface;
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_ReadBuffer;
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_ReadBuffer;
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_OffScreenReadBuffer;
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_OffScreenReadBuffer;
|
|
||||||
|
|
||||||
D3DFORMAT FramebufferManager::s_efb_color_surface_Format;
|
|
||||||
D3DFORMAT FramebufferManager::s_efb_depth_surface_Format;
|
|
||||||
D3DFORMAT FramebufferManager::s_efb_depth_ReadBuffer_Format;
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorRTSurface()
|
|
||||||
{
|
|
||||||
return s_efb_color_surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthRTSurface()
|
|
||||||
{
|
|
||||||
return s_efb_depth_surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorOffScreenRTSurface()
|
|
||||||
{
|
|
||||||
return s_efb_color_OffScreenReadBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthOffScreenRTSurface()
|
|
||||||
{
|
|
||||||
return s_efb_depth_OffScreenReadBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorReadSurface()
|
|
||||||
{
|
|
||||||
return s_efb_color_ReadBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthReadSurface()
|
|
||||||
{
|
|
||||||
return s_efb_depth_ReadBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DFORMAT FramebufferManager::GetEFBDepthRTSurfaceFormat()
|
|
||||||
{
|
|
||||||
return s_efb_depth_surface_Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DFORMAT FramebufferManager::GetEFBDepthReadSurfaceFormat()
|
|
||||||
{
|
|
||||||
return s_efb_depth_ReadBuffer_Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat()
|
|
||||||
{
|
|
||||||
return s_efb_color_surface_Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
return s_efb_color_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc)
|
|
||||||
{
|
|
||||||
return s_efb_depth_texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferManager::FramebufferManager()
|
|
||||||
{
|
|
||||||
s_efb_color_texture = NULL;
|
|
||||||
LPDIRECT3DTEXTURE9 s_efb_colorRead_texture = NULL;
|
|
||||||
LPDIRECT3DTEXTURE9 s_efb_depth_texture = NULL;
|
|
||||||
LPDIRECT3DTEXTURE9 s_efb_depthRead_texture = NULL;
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_depth_surface = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_color_surface = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer = NULL;
|
|
||||||
|
|
||||||
D3DFORMAT s_efb_color_surface_Format = D3DFMT_FORCE_DWORD;
|
|
||||||
D3DFORMAT s_efb_depth_surface_Format = D3DFMT_FORCE_DWORD;
|
|
||||||
D3DFORMAT s_efb_depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD;
|
|
||||||
m_realXFBSource.texture = NULL;
|
|
||||||
|
|
||||||
// Simplest possible setup to start with.
|
|
||||||
int target_width = Renderer::GetFullTargetWidth();
|
|
||||||
int target_height = Renderer::GetFullTargetHeight();
|
|
||||||
|
|
||||||
s_efb_color_surface_Format = D3DFMT_A8R8G8B8;
|
|
||||||
// Get the framebuffer texture
|
|
||||||
HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
||||||
D3DPOOL_DEFAULT, &s_efb_color_texture, NULL);
|
|
||||||
if(s_efb_color_texture)
|
|
||||||
{
|
|
||||||
hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface);
|
|
||||||
}
|
|
||||||
CHECK(hr, "Create color texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
|
||||||
hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
||||||
D3DPOOL_DEFAULT, &s_efb_colorRead_texture, NULL);
|
|
||||||
CHECK(hr, "Create Color Read Texture (hr=%#x)", hr);
|
|
||||||
if(s_efb_colorRead_texture)
|
|
||||||
{
|
|
||||||
s_efb_colorRead_texture->GetSurfaceLevel(0, &s_efb_color_ReadBuffer);
|
|
||||||
}
|
|
||||||
// Create an offscreen surface that we can lock to retrieve the data
|
|
||||||
hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_color_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL);
|
|
||||||
CHECK(hr, "Create offscreen color surface (hr=%#x)", hr);
|
|
||||||
|
|
||||||
// Select a Z-buffer format with hardware support
|
|
||||||
D3DFORMAT *DepthTexFormats = new D3DFORMAT[5];
|
|
||||||
DepthTexFormats[0] = FOURCC_INTZ;
|
|
||||||
DepthTexFormats[1] = FOURCC_DF24;
|
|
||||||
DepthTexFormats[2] = FOURCC_RAWZ;
|
|
||||||
DepthTexFormats[3] = FOURCC_DF16;
|
|
||||||
DepthTexFormats[4] = D3DFMT_D24X8;
|
|
||||||
|
|
||||||
for(int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
s_efb_depth_surface_Format = DepthTexFormats[i];
|
|
||||||
// Create the framebuffer depth texture
|
|
||||||
hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format,
|
|
||||||
D3DPOOL_DEFAULT, &s_efb_depth_texture, NULL);
|
|
||||||
if (!FAILED(hr))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CHECK(hr, "Framebuffer depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
|
||||||
// Get the Surface
|
|
||||||
if(s_efb_depth_texture)
|
|
||||||
{
|
|
||||||
s_efb_depth_texture->GetSurfaceLevel(0, &s_efb_depth_surface);
|
|
||||||
}
|
|
||||||
// Create a 4x4 pixel texture to work as a buffer for peeking
|
|
||||||
if(s_efb_depth_surface_Format == FOURCC_RAWZ || s_efb_depth_surface_Format == D3DFMT_D24X8)
|
|
||||||
{
|
|
||||||
DepthTexFormats[0] = D3DFMT_A8R8G8B8;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DepthTexFormats[0] = D3DFMT_R32F;
|
|
||||||
}
|
|
||||||
DepthTexFormats[1] = D3DFMT_A8R8G8B8;
|
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
s_efb_depth_ReadBuffer_Format = DepthTexFormats[i];
|
|
||||||
// Get the framebuffer Depth texture
|
|
||||||
hr = D3D::dev->CreateTexture(4, 4, 1, D3DUSAGE_RENDERTARGET, s_efb_depth_ReadBuffer_Format,
|
|
||||||
D3DPOOL_DEFAULT, &s_efb_depthRead_texture, NULL);
|
|
||||||
if (!FAILED(hr))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECK(hr, "Create depth read texture (hr=%#x)", hr);
|
|
||||||
if(s_efb_depthRead_texture)
|
|
||||||
{
|
|
||||||
s_efb_depthRead_texture->GetSurfaceLevel(0, &s_efb_depth_ReadBuffer);
|
|
||||||
}
|
|
||||||
// Create an offscreen surface that we can lock to retrieve the data
|
|
||||||
hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb_depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL);
|
|
||||||
CHECK(hr, "Create depth offscreen surface (hr=%#x)", hr);
|
|
||||||
delete [] DepthTexFormats;
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferManager::~FramebufferManager()
|
|
||||||
{
|
|
||||||
SAFE_RELEASE(s_efb_depth_surface);
|
|
||||||
SAFE_RELEASE(s_efb_color_surface);
|
|
||||||
SAFE_RELEASE(s_efb_color_ReadBuffer);
|
|
||||||
SAFE_RELEASE(s_efb_depth_ReadBuffer);
|
|
||||||
SAFE_RELEASE(s_efb_color_OffScreenReadBuffer);
|
|
||||||
SAFE_RELEASE(s_efb_depth_OffScreenReadBuffer);
|
|
||||||
SAFE_RELEASE(s_efb_color_texture);
|
|
||||||
SAFE_RELEASE(s_efb_colorRead_texture);
|
|
||||||
SAFE_RELEASE(s_efb_depth_texture);
|
|
||||||
SAFE_RELEASE(s_efb_depthRead_texture);
|
|
||||||
|
|
||||||
if (m_realXFBSource.texture)
|
|
||||||
m_realXFBSource.texture->Release();
|
|
||||||
m_realXFBSource.texture = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
//u8* xfb_in_ram = Memory_GetPtr(xfbAddr);
|
|
||||||
//if (!xfb_in_ram)
|
|
||||||
//{
|
|
||||||
// WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc);
|
|
||||||
//TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
//xfbCount = 1;
|
|
||||||
|
|
||||||
//m_realXFBSource.texWidth = fbWidth;
|
|
||||||
//m_realXFBSource.texHeight = fbHeight;
|
|
||||||
|
|
||||||
//m_realXFBSource.srcAddr = xfbAddr;
|
|
||||||
//m_realXFBSource.srcWidth = fbWidth;
|
|
||||||
//m_realXFBSource.srcHeight = fbHeight;
|
|
||||||
|
|
||||||
//if (!m_realXFBSource.texture)
|
|
||||||
//{
|
|
||||||
// D3D::dev->CreateTexture(fbWidth, fbHeight, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
||||||
// D3DPOOL_DEFAULT, &m_realXFBSource.texture, NULL);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//// Decode YUYV data from GameCube RAM
|
|
||||||
//TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture);
|
|
||||||
|
|
||||||
//m_overlappingXFBArray[0] = &m_realXFBSource;
|
|
||||||
|
|
||||||
//return &m_overlappingXFBArray[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
XFBSourceBase *FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
|
||||||
{
|
|
||||||
XFBSource* const xfbs = new XFBSource;
|
|
||||||
D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format,
|
|
||||||
D3DPOOL_DEFAULT, &xfbs->texture, NULL);
|
|
||||||
|
|
||||||
return xfbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFBSource::~XFBSource()
|
|
||||||
{
|
|
||||||
texture->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFBSource::CopyEFB(const TargetRectangle& efbSource)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,130 +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 _FRAMEBUFFERMANAGER_D3D_H_
|
|
||||||
#define _FRAMEBUFFERMANAGER_D3D_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
#include "../FramebufferManager.h"
|
|
||||||
|
|
||||||
// On the GameCube, the game sends a request for the graphics processor to
|
|
||||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
|
||||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
|
||||||
// decided at the time of the copy, and the format is always YUYV. The video
|
|
||||||
// interface is given a pointer to the XFB, which will be decoded and
|
|
||||||
// displayed on the TV.
|
|
||||||
//
|
|
||||||
// There are two ways for Dolphin to emulate this:
|
|
||||||
//
|
|
||||||
// Real XFB mode:
|
|
||||||
//
|
|
||||||
// Dolphin will behave like the GameCube and encode the EFB to
|
|
||||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
|
||||||
// for output to the screen.
|
|
||||||
//
|
|
||||||
// Advantages: Behaves exactly like the GameCube.
|
|
||||||
// Disadvantages: Resolution will be limited.
|
|
||||||
//
|
|
||||||
// Virtual XFB mode:
|
|
||||||
//
|
|
||||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
|
||||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
|
||||||
// The video interface will look up the XFB in the list and use the enhanced
|
|
||||||
// data stored there, if available.
|
|
||||||
//
|
|
||||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
|
||||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
|
||||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
|
||||||
|
|
||||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
|
||||||
// virtualize.
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
const int MAX_VIRTUAL_XFB = 8;
|
|
||||||
|
|
||||||
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
|
|
||||||
{
|
|
||||||
return !((aLower >= bUpper) || (bLower >= aUpper));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct XFBSource : public XFBSourceBase
|
|
||||||
{
|
|
||||||
XFBSource() : texture(NULL) {}
|
|
||||||
~XFBSource();
|
|
||||||
|
|
||||||
void CopyEFB(const TargetRectangle& efbSource);
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 texture;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FramebufferManager : public ::FramebufferManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FramebufferManager();
|
|
||||||
~FramebufferManager();
|
|
||||||
|
|
||||||
void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
XFBSourceBase *CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
|
||||||
|
|
||||||
static LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc);
|
|
||||||
static LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBColorRTSurface();
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBDepthRTSurface();
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface();
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface();
|
|
||||||
static D3DFORMAT GetEFBDepthRTSurfaceFormat();
|
|
||||||
static D3DFORMAT GetEFBColorRTSurfaceFormat();
|
|
||||||
static D3DFORMAT GetEFBDepthReadSurfaceFormat();
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBColorReadSurface();
|
|
||||||
static LPDIRECT3DSURFACE9 GetEFBDepthReadSurface();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
|
||||||
|
|
||||||
static XFBSource m_realXFBSource; // Only used in Real XFB mode
|
|
||||||
|
|
||||||
const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB];
|
|
||||||
|
|
||||||
static LPDIRECT3DTEXTURE9 s_efb_color_texture;//Texture thats contains the color data of the render target
|
|
||||||
static LPDIRECT3DTEXTURE9 s_efb_colorRead_texture;//1 pixel texture for temporal data store
|
|
||||||
static LPDIRECT3DTEXTURE9 s_efb_depth_texture;//Texture thats contains the depth data of the render target
|
|
||||||
static LPDIRECT3DTEXTURE9 s_efb_depthRead_texture;//4 pixel texture for temporal data store
|
|
||||||
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_depth_surface;//Depth Surface
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_color_surface;//Color Surface
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;//Surface 0 of s_efb_colorRead_texture
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;//Surface 0 of s_efb_depthRead_texture
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data
|
|
||||||
static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data
|
|
||||||
|
|
||||||
static D3DFORMAT s_efb_color_surface_Format;//Format of the color Surface
|
|
||||||
static D3DFORMAT s_efb_depth_surface_Format;//Format of the Depth Surface
|
|
||||||
static D3DFORMAT s_efb_depth_ReadBuffer_Format;//Format of the Depth color Read Surface
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,178 +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 "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "x64Emitter.h"
|
|
||||||
#include "ABI.h"
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
#include "CPMemory.h"
|
|
||||||
|
|
||||||
#include "DX9_VertexManager.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
class D3DVertexFormat : public NativeVertexFormat
|
|
||||||
{
|
|
||||||
LPDIRECT3DVERTEXDECLARATION9 d3d_decl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
D3DVertexFormat();
|
|
||||||
~D3DVertexFormat();
|
|
||||||
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
|
||||||
virtual void SetupVertexPointers() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
NativeVertexFormat *VertexManager::CreateNativeVertexFormat()
|
|
||||||
{
|
|
||||||
return new D3DVertexFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DVertexFormat::~D3DVertexFormat()
|
|
||||||
{
|
|
||||||
if (d3d_decl)
|
|
||||||
{
|
|
||||||
d3d_decl->Release();
|
|
||||||
d3d_decl = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DDECLTYPE VarToD3D(VarType t, int size)
|
|
||||||
{
|
|
||||||
if (t < 0 || t > 4) {
|
|
||||||
PanicAlert("VarToD3D: Invalid VarType %i", t);
|
|
||||||
}
|
|
||||||
static const D3DDECLTYPE lookup1[5] = {
|
|
||||||
D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT1,
|
|
||||||
};
|
|
||||||
static const D3DDECLTYPE lookup2[5] = {
|
|
||||||
D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_SHORT2N, D3DDECLTYPE_USHORT2N, D3DDECLTYPE_FLOAT2,
|
|
||||||
};
|
|
||||||
static const D3DDECLTYPE lookup3[5] = {
|
|
||||||
D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT3,
|
|
||||||
};
|
|
||||||
// Sadly, D3D9 has no SBYTE4N. D3D10 does, though.
|
|
||||||
static const D3DDECLTYPE lookup4[5] = {
|
|
||||||
D3DDECLTYPE_UNUSED, D3DDECLTYPE_UBYTE4N, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT4,
|
|
||||||
};
|
|
||||||
D3DDECLTYPE retval = D3DDECLTYPE_UNUSED;
|
|
||||||
switch (size) {
|
|
||||||
case 1: retval = lookup1[t]; break;
|
|
||||||
case 2: retval = lookup2[t]; break;
|
|
||||||
case 3: retval = lookup3[t]; break;
|
|
||||||
case 4: retval = lookup4[t]; break;
|
|
||||||
default: PanicAlert("VarToD3D: size wrong (%i)", size); break;
|
|
||||||
}
|
|
||||||
if (retval == D3DDECLTYPE_UNUSED) {
|
|
||||||
PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
|
||||||
{
|
|
||||||
vertex_stride = _vtx_decl.stride;
|
|
||||||
|
|
||||||
D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32];
|
|
||||||
memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32);
|
|
||||||
|
|
||||||
// There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream.
|
|
||||||
// Same for method.
|
|
||||||
|
|
||||||
// So, here we go. First position:
|
|
||||||
int elem_idx = 0;
|
|
||||||
elems[elem_idx].Offset = 0; // Positions are always first, at position 0. Always float3.
|
|
||||||
elems[elem_idx].Type = D3DDECLTYPE_FLOAT3;
|
|
||||||
elems[elem_idx].Usage = D3DDECLUSAGE_POSITION;
|
|
||||||
++elem_idx;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.normal_offset[i] > 0)
|
|
||||||
{
|
|
||||||
elems[elem_idx].Offset = _vtx_decl.normal_offset[i];
|
|
||||||
elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size);
|
|
||||||
elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL;
|
|
||||||
elems[elem_idx].UsageIndex = i;
|
|
||||||
++elem_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.color_offset[i] > 0)
|
|
||||||
{
|
|
||||||
elems[elem_idx].Offset = _vtx_decl.color_offset[i];
|
|
||||||
elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type, 4);
|
|
||||||
elems[elem_idx].Usage = D3DDECLUSAGE_COLOR;
|
|
||||||
elems[elem_idx].UsageIndex = i;
|
|
||||||
++elem_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if (_vtx_decl.texcoord_offset[i] > 0)
|
|
||||||
{
|
|
||||||
elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i];
|
|
||||||
elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]);
|
|
||||||
elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD;
|
|
||||||
elems[elem_idx].UsageIndex = i;
|
|
||||||
++elem_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_vtx_decl.posmtx_offset != -1)
|
|
||||||
{
|
|
||||||
elems[elem_idx].Offset = _vtx_decl.posmtx_offset;
|
|
||||||
elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES;
|
|
||||||
elems[elem_idx].Type = D3DDECLTYPE_D3DCOLOR;
|
|
||||||
elems[elem_idx].UsageIndex = 0;
|
|
||||||
++elem_idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End marker
|
|
||||||
elems[elem_idx].Stream = 0xff;
|
|
||||||
elems[elem_idx].Type = D3DDECLTYPE_UNUSED;
|
|
||||||
++elem_idx;
|
|
||||||
|
|
||||||
if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl)))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create D3D vertex declaration!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delete [] elems;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DVertexFormat::SetupVertexPointers() const
|
|
||||||
{
|
|
||||||
if (d3d_decl)
|
|
||||||
D3D::SetVertexDeclaration(d3d_decl);
|
|
||||||
else
|
|
||||||
ERROR_LOG(VIDEO, "invalid d3d decl");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,392 +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 <map>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Hash.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DShader.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "XFMemory.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
//#include "Debugger/Debugger.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
|
||||||
const PixelShaderCache::PSCacheEntry *PixelShaderCache::last_entry;
|
|
||||||
|
|
||||||
static LinearDiskCache g_ps_disk_cache;
|
|
||||||
static std::set<u32> unique_shaders;
|
|
||||||
|
|
||||||
#define MAX_SSAA_SHADERS 3
|
|
||||||
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_ColorMatrixProgram[MAX_SSAA_SHADERS];
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_ColorCopyProgram[MAX_SSAA_SHADERS];
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_DepthMatrixProgram[MAX_SSAA_SHADERS];
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_ClearProgram = 0;
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram(int SSAAMode)
|
|
||||||
{
|
|
||||||
return s_ColorMatrixProgram[SSAAMode % MAX_SSAA_SHADERS];
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetDepthMatrixProgram(int SSAAMode)
|
|
||||||
{
|
|
||||||
return s_DepthMatrixProgram[SSAAMode % MAX_SSAA_SHADERS];
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorCopyProgram(int SSAAMode)
|
|
||||||
{
|
|
||||||
return s_ColorCopyProgram[SSAAMode % MAX_SSAA_SHADERS];
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetClearProgram()
|
|
||||||
{
|
|
||||||
return s_ClearProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
float f[4] = { f1, f2, f3, f4 };
|
|
||||||
D3D::dev->SetPixelShaderConstantF(const_number, f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f)
|
|
||||||
{
|
|
||||||
D3D::dev->SetPixelShaderConstantF(const_number, f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
D3D::dev->SetPixelShaderConstantF(const_number, f, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PixelShaderCacheInserter : public LinearDiskCacheReader {
|
|
||||||
public:
|
|
||||||
void Read(const u8 *key, int key_size, const u8 *value, int value_size)
|
|
||||||
{
|
|
||||||
PIXELSHADERUID uid;
|
|
||||||
if (key_size != sizeof(uid)) {
|
|
||||||
ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&uid, key, key_size);
|
|
||||||
PixelShaderCache::InsertByteCode(uid, value, value_size, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PixelShaderCache::PixelShaderCache()
|
|
||||||
{
|
|
||||||
//program used for clear screen
|
|
||||||
char pprog[3072];
|
|
||||||
sprintf(pprog, "void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
" in float4 incol0 : COLOR0){\n"
|
|
||||||
"ocol0 = incol0;\n"
|
|
||||||
"}\n");
|
|
||||||
s_ClearProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//Used for Copy/resolve the color buffer
|
|
||||||
//1 Sample
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"ocol0 = tex2D(samp0,uv0);\n"
|
|
||||||
"}\n");
|
|
||||||
s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//1 Samples SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1){\n"
|
|
||||||
"ocol0 = tex2D(samp0,uv0.xy);\n"
|
|
||||||
"}\n");
|
|
||||||
s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//4 Samples SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1,\n"
|
|
||||||
"in float4 uv2 : TEXCOORD2,\n"
|
|
||||||
"in float4 uv3 : TEXCOORD3){\n"
|
|
||||||
"ocol0 = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25;\n"
|
|
||||||
"}\n");
|
|
||||||
s_ColorCopyProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Color conversion Programs
|
|
||||||
//1 sample
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
" in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"float4 texcol = tex2D(samp0,uv0);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//1 samples SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1){\n"
|
|
||||||
"float4 texcol = tex2D(samp0,uv0.xy);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//4 samples SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1,\n"
|
|
||||||
"in float4 uv2 : TEXCOORD2,\n"
|
|
||||||
"in float4 uv3 : TEXCOORD3){\n"
|
|
||||||
"float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_ColorMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//Depth copy programs
|
|
||||||
//1 sample
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
" in float2 uv0 : TEXCOORD0){\n"
|
|
||||||
"float4 texcol = tex2D(samp0,uv0);\n"
|
|
||||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
|
|
||||||
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//1 sample SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1){\n"
|
|
||||||
"float4 texcol = tex2D(samp0,uv0.xy);\n"
|
|
||||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
|
|
||||||
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
//4 sample SSAA
|
|
||||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
|
||||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
|
||||||
"void main(\n"
|
|
||||||
"out float4 ocol0 : COLOR0,\n"
|
|
||||||
"in float4 uv0 : TEXCOORD0,\n"
|
|
||||||
"in float4 uv1 : TEXCOORD1,\n"
|
|
||||||
"in float4 uv2 : TEXCOORD2,\n"
|
|
||||||
"in float4 uv3 : TEXCOORD3){\n"
|
|
||||||
"float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n"
|
|
||||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
|
|
||||||
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
|
|
||||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
|
||||||
"}\n",C_COLORMATRIX);
|
|
||||||
s_DepthMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
|
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
SETSTAT(stats.numPixelShadersCreated, 0);
|
|
||||||
SETSTAT(stats.numPixelShadersAlive, 0);
|
|
||||||
|
|
||||||
char cache_filename[MAX_PATH];
|
|
||||||
sprintf(cache_filename, "%sdx9-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
|
|
||||||
PixelShaderCacheInserter inserter;
|
|
||||||
int read_items = g_ps_disk_cache.OpenAndRead(cache_filename, &inserter);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ONLY to be used during shutdown.
|
|
||||||
void PixelShaderCache::Clear()
|
|
||||||
{
|
|
||||||
PSCache::iterator iter = PixelShaders.begin();
|
|
||||||
for (; iter != PixelShaders.end(); ++iter)
|
|
||||||
iter->second.Destroy();
|
|
||||||
PixelShaders.clear();
|
|
||||||
|
|
||||||
memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid));
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelShaderCache::~PixelShaderCache()
|
|
||||||
{
|
|
||||||
for(int i = 0;i < MAX_SSAA_SHADERS; i++)
|
|
||||||
{
|
|
||||||
if (s_ColorMatrixProgram[i]) s_ColorMatrixProgram[i]->Release();
|
|
||||||
s_ColorMatrixProgram[i] = NULL;
|
|
||||||
if (s_ColorCopyProgram[i]) s_ColorCopyProgram[i]->Release();
|
|
||||||
s_ColorCopyProgram[i] = NULL;
|
|
||||||
if (s_DepthMatrixProgram[i]) s_DepthMatrixProgram[i]->Release();
|
|
||||||
s_DepthMatrixProgram[i] = NULL;
|
|
||||||
}
|
|
||||||
if (s_ClearProgram) s_ClearProgram->Release();
|
|
||||||
s_ClearProgram = NULL;
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
g_ps_disk_cache.Sync();
|
|
||||||
g_ps_disk_cache.Close();
|
|
||||||
|
|
||||||
unique_shaders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PixelShaderCache::SetShader(bool dstAlpha)
|
|
||||||
{
|
|
||||||
PIXELSHADERUID uid;
|
|
||||||
GetPixelShaderId(&uid, dstAlpha);
|
|
||||||
|
|
||||||
// Is the shader already set?
|
|
||||||
if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount)
|
|
||||||
{
|
|
||||||
PSCache::const_iterator iter = PixelShaders.find(uid);
|
|
||||||
if (iter != PixelShaders.end() && iter->second.shader)
|
|
||||||
return true; // Sure, we're done.
|
|
||||||
else
|
|
||||||
return false; // ?? something is wrong.
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
|
|
||||||
|
|
||||||
// Is the shader already in the cache?
|
|
||||||
PSCache::iterator iter;
|
|
||||||
iter = PixelShaders.find(uid);
|
|
||||||
if (iter != PixelShaders.end())
|
|
||||||
{
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
const PSCacheEntry &entry = iter->second;
|
|
||||||
last_entry = &entry;
|
|
||||||
|
|
||||||
if (entry.shader)
|
|
||||||
{
|
|
||||||
D3D::SetPixelShader(entry.shader);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK, need to generate and compile it.
|
|
||||||
const char *code = GeneratePixelShaderCode(dstAlpha, API_D3D9);
|
|
||||||
|
|
||||||
u32 code_hash = HashAdler32((const u8 *)code, strlen(code));
|
|
||||||
unique_shaders.insert(code_hash);
|
|
||||||
SETSTAT(stats.numUniquePixelShaders, unique_shaders.size());
|
|
||||||
|
|
||||||
#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), counter++);
|
|
||||||
|
|
||||||
SaveData(szTemp, code);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u8 *bytecode = 0;
|
|
||||||
int bytecodelen = 0;
|
|
||||||
if (!D3D::CompilePixelShader(code, (int)strlen(code), &bytecode, &bytecodelen)) {
|
|
||||||
if (g_ActiveConfig.bShowShaderErrors)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to compile Pixel Shader:\n\n%s", code);
|
|
||||||
static int counter = 0;
|
|
||||||
char szTemp[MAX_PATH];
|
|
||||||
sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++);
|
|
||||||
SaveData(szTemp, code);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we have the UID and the byte code. Insert it into the disk cache.
|
|
||||||
g_ps_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen);
|
|
||||||
g_ps_disk_cache.Sync();
|
|
||||||
|
|
||||||
// And insert it into the shader cache.
|
|
||||||
bool result = InsertByteCode(uid, bytecode, bytecodelen, true);
|
|
||||||
delete [] bytecode;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) {
|
|
||||||
LPDIRECT3DPIXELSHADER9 shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
|
||||||
|
|
||||||
// Make an entry in the table
|
|
||||||
PSCacheEntry newentry;
|
|
||||||
newentry.shader = shader;
|
|
||||||
newentry.frameCount = frameCount;
|
|
||||||
PixelShaders[uid] = newentry;
|
|
||||||
last_entry = &PixelShaders[uid];
|
|
||||||
|
|
||||||
if (!shader) {
|
|
||||||
// INCSTAT(stats.numPixelShadersFailed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
INCSTAT(stats.numPixelShadersCreated);
|
|
||||||
SETSTAT(stats.numPixelShadersAlive, (int)PixelShaders.size());
|
|
||||||
if (activate)
|
|
||||||
{
|
|
||||||
D3D::SetPixelShader(shader);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string PixelShaderCache::GetCurrentShaderCode()
|
|
||||||
{
|
|
||||||
if (last_entry)
|
|
||||||
return last_entry->code;
|
|
||||||
else
|
|
||||||
return "(no shader)\n";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,89 +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 "Common.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
#include "../PixelShaderCache.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
typedef u32 tevhash;
|
|
||||||
|
|
||||||
tevhash GetCurrentTEV();
|
|
||||||
|
|
||||||
class PixelShaderCache : public ::PixelShaderCacheBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
struct PSCacheEntry
|
|
||||||
{
|
|
||||||
LPDIRECT3DPIXELSHADER9 shader;
|
|
||||||
bool owns_shader;
|
|
||||||
int frameCount;
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string code;
|
|
||||||
#endif
|
|
||||||
PSCacheEntry() : shader(NULL), owns_shader(true), frameCount(0) {}
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
if (shader && owns_shader)
|
|
||||||
shader->Release();
|
|
||||||
shader = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
|
|
||||||
|
|
||||||
static PSCache PixelShaders;
|
|
||||||
static const PSCacheEntry *last_entry;
|
|
||||||
static void Clear();
|
|
||||||
|
|
||||||
public:
|
|
||||||
PixelShaderCache();
|
|
||||||
~PixelShaderCache();
|
|
||||||
|
|
||||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetPSConstant4fv(unsigned int const_number, const float* f);
|
|
||||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f);
|
|
||||||
|
|
||||||
bool SetShader(bool dstAlpha);
|
|
||||||
|
|
||||||
static bool InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate);
|
|
||||||
static LPDIRECT3DPIXELSHADER9 GetColorMatrixProgram(int SSAAMode);
|
|
||||||
static LPDIRECT3DPIXELSHADER9 GetColorCopyProgram(int SSAAMode);
|
|
||||||
static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram(int SSAAMode);
|
|
||||||
static LPDIRECT3DPIXELSHADER9 GetClearProgram();
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
static std::string GetCurrentShaderCode();
|
|
||||||
#endif
|
|
||||||
static LPDIRECT3DPIXELSHADER9 CompileCgShader(const char *pstrprogram);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _PIXELSHADERCACHE_H
|
|
|
@ -1,960 +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 <list>
|
|
||||||
#include <d3dx9.h>
|
|
||||||
#include <strsafe.h>
|
|
||||||
|
|
||||||
#include "StringUtil.h"
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Atomic.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "Thread.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "DX9_VertexManager.h"
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
#include "DX9_D3DUtil.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "VertexLoaderManager.h"
|
|
||||||
#include "DX9_TextureCache.h"
|
|
||||||
#include "EmuWindow.h"
|
|
||||||
#include "AVIDump.h"
|
|
||||||
#include "OnScreenDisplay.h"
|
|
||||||
#include "DX9_FramebufferManager.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "DX9_TextureConverter.h"
|
|
||||||
#include "DLCache.h"
|
|
||||||
|
|
||||||
//#include "debugger/debugger.h"
|
|
||||||
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
bool Renderer::IS_AMD;
|
|
||||||
|
|
||||||
// State translation lookup tables
|
|
||||||
static const D3DBLEND d3dSrcFactors[8] =
|
|
||||||
{
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_DESTCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_SRCALPHA,
|
|
||||||
D3DBLEND_INVSRCALPHA,
|
|
||||||
D3DBLEND_DESTALPHA,
|
|
||||||
D3DBLEND_INVDESTALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DBLEND d3dDestFactors[8] =
|
|
||||||
{
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_SRCCOLOR,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_SRCALPHA,
|
|
||||||
D3DBLEND_INVSRCALPHA,
|
|
||||||
D3DBLEND_DESTALPHA,
|
|
||||||
D3DBLEND_INVDESTALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DBLENDOP d3dLogicOpop[16] =
|
|
||||||
{
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_SUBTRACT,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_REVSUBTRACT,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_MAX,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
|
|
||||||
D3DBLENDOP_MAX,
|
|
||||||
D3DBLENDOP_MAX,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD,
|
|
||||||
D3DBLENDOP_ADD
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DBLEND d3dLogicOpSrcFactors[16] =
|
|
||||||
{
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_DESTCOLOR,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_DESTCOLOR,
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_ONE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DBLEND d3dLogicOpDestFactors[16] =
|
|
||||||
{
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_ZERO,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_SRCCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_INVDESTCOLOR,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_ONE,
|
|
||||||
D3DBLEND_INVSRCCOLOR,
|
|
||||||
D3DBLEND_ONE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DCULL d3dCullModes[4] =
|
|
||||||
{
|
|
||||||
D3DCULL_NONE,
|
|
||||||
D3DCULL_CCW,
|
|
||||||
D3DCULL_CW,
|
|
||||||
D3DCULL_CCW
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DCMPFUNC d3dCmpFuncs[8] =
|
|
||||||
{
|
|
||||||
D3DCMP_NEVER,
|
|
||||||
D3DCMP_LESS,
|
|
||||||
D3DCMP_EQUAL,
|
|
||||||
D3DCMP_LESSEQUAL,
|
|
||||||
D3DCMP_GREATER,
|
|
||||||
D3DCMP_NOTEQUAL,
|
|
||||||
D3DCMP_GREATEREQUAL,
|
|
||||||
D3DCMP_ALWAYS
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
|
|
||||||
{
|
|
||||||
D3DTEXF_NONE,
|
|
||||||
D3DTEXF_POINT,
|
|
||||||
D3DTEXF_LINEAR,
|
|
||||||
D3DTEXF_NONE, //reserved
|
|
||||||
};
|
|
||||||
|
|
||||||
static const D3DTEXTUREADDRESS d3dClamps[4] =
|
|
||||||
{
|
|
||||||
D3DTADDRESS_CLAMP,
|
|
||||||
D3DTADDRESS_WRAP,
|
|
||||||
D3DTADDRESS_MIRROR,
|
|
||||||
D3DTADDRESS_WRAP //reserved
|
|
||||||
};
|
|
||||||
|
|
||||||
void Renderer::SetupDeviceObjects()
|
|
||||||
{
|
|
||||||
D3D::font.Init();
|
|
||||||
g_framebuffer_manager = new FramebufferManager;
|
|
||||||
|
|
||||||
VertexShaderManager::Dirty();
|
|
||||||
PixelShaderManager::Dirty();
|
|
||||||
// TODO:
|
|
||||||
//TextureConverter::Init();
|
|
||||||
|
|
||||||
// To avoid shader compilation stutters, read back all shaders from cache.
|
|
||||||
// Texture cache will recreate themselves over time.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill off all POOL_DEFAULT device objects.
|
|
||||||
void Renderer::TeardownDeviceObjects()
|
|
||||||
{
|
|
||||||
D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
|
|
||||||
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
|
|
||||||
//D3D::font.Shutdown();
|
|
||||||
// TODO:
|
|
||||||
//TextureConverter::Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::Renderer()
|
|
||||||
{
|
|
||||||
UpdateActiveConfig();
|
|
||||||
int fullScreenRes, x, y, w_temp, h_temp;
|
|
||||||
s_blendMode = 0;
|
|
||||||
// Multisample Anti-aliasing hasn't been implemented yet use supersamling instead
|
|
||||||
int backbuffer_ms_mode = 0;
|
|
||||||
|
|
||||||
g_VideoInitialize.pRequestWindowSize(x, y, w_temp, h_temp);
|
|
||||||
|
|
||||||
for (fullScreenRes = 0; fullScreenRes < (int)D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size(); fullScreenRes++)
|
|
||||||
{
|
|
||||||
if ((D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].xres == w_temp) &&
|
|
||||||
(D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].yres == h_temp))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fullScreenRes == D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size())
|
|
||||||
fullScreenRes = 0;
|
|
||||||
|
|
||||||
D3D::Init();
|
|
||||||
|
|
||||||
D3D::Create(g_ActiveConfig.iAdapter, EmuWindow::GetWnd(),
|
|
||||||
fullScreenRes, backbuffer_ms_mode, false);
|
|
||||||
|
|
||||||
IS_AMD = D3D::IsATIDevice();
|
|
||||||
s_backbuffer_width = D3D::GetBackBufferWidth();
|
|
||||||
s_backbuffer_height = D3D::GetBackBufferHeight();
|
|
||||||
|
|
||||||
s_XFB_width = MAX_XFB_WIDTH;
|
|
||||||
s_XFB_height = MAX_XFB_HEIGHT;
|
|
||||||
|
|
||||||
FramebufferSize(s_backbuffer_width, s_backbuffer_height);
|
|
||||||
|
|
||||||
// We're not using fixed function.
|
|
||||||
// Let's just set the matrices to identity to be sure.
|
|
||||||
D3DXMATRIX mtx;
|
|
||||||
D3DXMatrixIdentity(&mtx);
|
|
||||||
D3D::dev->SetTransform(D3DTS_VIEW, &mtx);
|
|
||||||
D3D::dev->SetTransform(D3DTS_WORLD, &mtx);
|
|
||||||
|
|
||||||
SetupDeviceObjects();
|
|
||||||
|
|
||||||
for (int stage = 0; stage < 8; stage++)
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, g_ActiveConfig.iMaxAnisotropy);
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = s_backbuffer_width;
|
|
||||||
vp.Height = s_backbuffer_height;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, 0x0, 0, 0);
|
|
||||||
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
vp.X = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
vp.Y = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
vp.Width = s_target_width;
|
|
||||||
vp.Height = s_target_height;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0);
|
|
||||||
D3D::BeginFrame();
|
|
||||||
D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true);
|
|
||||||
//return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::~Renderer()
|
|
||||||
{
|
|
||||||
TeardownDeviceObjects();
|
|
||||||
D3D::EndFrame();
|
|
||||||
D3D::Present();
|
|
||||||
D3D::Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void formatBufferDump(const char *in, char *out, int w, int h, int p)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < h; y++)
|
|
||||||
{
|
|
||||||
const char *line = in + (h - y - 1) * p;
|
|
||||||
for (int x = 0; x < w; x++)
|
|
||||||
{
|
|
||||||
memcpy(out, line, 3);
|
|
||||||
out += 3;
|
|
||||||
line += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// With D3D, we have to resize the backbuffer if the window changed
|
|
||||||
// size.
|
|
||||||
bool Renderer::CheckForResize()
|
|
||||||
{
|
|
||||||
while (EmuWindow::IsSizing())
|
|
||||||
{
|
|
||||||
Sleep(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EmuWindow::GetParentWnd())
|
|
||||||
{
|
|
||||||
// Re-stretch window to parent window size again, if it has a parent window.
|
|
||||||
RECT rcParentWindow;
|
|
||||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow);
|
|
||||||
int width = rcParentWindow.right - rcParentWindow.left;
|
|
||||||
int height = rcParentWindow.bottom - rcParentWindow.top;
|
|
||||||
if (width != s_backbuffer_width || height != s_backbuffer_height)
|
|
||||||
MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
|
||||||
}
|
|
||||||
RECT rcWindow;
|
|
||||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
|
||||||
int client_width = rcWindow.right - rcWindow.left;
|
|
||||||
int client_height = rcWindow.bottom - rcWindow.top;
|
|
||||||
// Sanity check.
|
|
||||||
if ((client_width != s_backbuffer_width ||
|
|
||||||
client_height != s_backbuffer_height) &&
|
|
||||||
client_width >= 4 && client_height >= 4)
|
|
||||||
{
|
|
||||||
TeardownDeviceObjects();
|
|
||||||
|
|
||||||
D3D::Reset();
|
|
||||||
s_backbuffer_width = D3D::GetBackBufferWidth();
|
|
||||||
s_backbuffer_height = D3D::GetBackBufferHeight();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::SetScissorRect()
|
|
||||||
{
|
|
||||||
EFBRectangle rc;
|
|
||||||
if (g_renderer->SetScissorRect(rc))
|
|
||||||
{
|
|
||||||
D3D::dev->SetScissorRect((RECT*)&rc);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom);
|
|
||||||
const int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
const int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
rc.left = Xstride;
|
|
||||||
rc.top = Ystride;
|
|
||||||
rc.right = Xstride + s_target_width;
|
|
||||||
rc.bottom = Ystride + s_target_height;
|
|
||||||
|
|
||||||
D3D::dev->SetScissorRect((RECT*)&rc);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetColorMask()
|
|
||||||
{
|
|
||||||
DWORD color_mask = 0;
|
|
||||||
if (bpmem.blendmode.alphaupdate)
|
|
||||||
color_mask = D3DCOLORWRITEENABLE_ALPHA;
|
|
||||||
if (bpmem.blendmode.colorupdate)
|
|
||||||
color_mask |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
|
|
||||||
D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
|
||||||
{
|
|
||||||
if (!g_ActiveConfig.bEFBAccessEnable)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (type == POKE_Z || type == POKE_COLOR)
|
|
||||||
{
|
|
||||||
static bool alert_only_once = true;
|
|
||||||
if (!alert_only_once) return 0;
|
|
||||||
PanicAlert("Poke EFB not implemented");
|
|
||||||
alert_only_once = false;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the working buffer
|
|
||||||
LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ?
|
|
||||||
FramebufferManager::GetEFBDepthRTSurface() : FramebufferManager::GetEFBColorRTSurface();
|
|
||||||
// Get the temporal buffer to move 1pixel data
|
|
||||||
LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ?
|
|
||||||
FramebufferManager::GetEFBDepthReadSurface() : FramebufferManager::GetEFBColorReadSurface();
|
|
||||||
// Get the memory buffer that can be locked
|
|
||||||
LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ?
|
|
||||||
FramebufferManager::GetEFBDepthOffScreenRTSurface() : FramebufferManager::GetEFBColorOffScreenRTSurface();
|
|
||||||
// Get the buffer format
|
|
||||||
D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ?
|
|
||||||
FramebufferManager::GetEFBDepthRTSurfaceFormat() : FramebufferManager::GetEFBColorRTSurfaceFormat();
|
|
||||||
D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ?
|
|
||||||
FramebufferManager::GetEFBDepthReadSurfaceFormat() : BufferFormat;
|
|
||||||
|
|
||||||
if (BufferFormat == D3DFMT_D24X8)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
D3DLOCKED_RECT drect;
|
|
||||||
|
|
||||||
// Buffer not found alert
|
|
||||||
if (!pBuffer) {
|
|
||||||
PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Get the rectangular target region covered by the EFB pixel.
|
|
||||||
|
|
||||||
EFBRectangle efbPixelRc;
|
|
||||||
efbPixelRc.left = x;
|
|
||||||
efbPixelRc.top = y;
|
|
||||||
efbPixelRc.right = x + 1;
|
|
||||||
efbPixelRc.bottom = y + 1;
|
|
||||||
|
|
||||||
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
|
|
||||||
|
|
||||||
u32 z = 0;
|
|
||||||
float val = 0.0f;
|
|
||||||
HRESULT hr;
|
|
||||||
RECT RectToLock;
|
|
||||||
RectToLock.bottom = targetPixelRc.bottom;
|
|
||||||
RectToLock.left = targetPixelRc.left;
|
|
||||||
RectToLock.right = targetPixelRc.right;
|
|
||||||
RectToLock.top = targetPixelRc.top;
|
|
||||||
if (type == PEEK_Z)
|
|
||||||
{
|
|
||||||
RECT PixelRect;
|
|
||||||
PixelRect.bottom = 4;
|
|
||||||
PixelRect.left = 0;
|
|
||||||
PixelRect.right = 4;
|
|
||||||
PixelRect.top = 0;
|
|
||||||
RectToLock.bottom+=2;
|
|
||||||
RectToLock.right+=1;
|
|
||||||
RectToLock.top-=1;
|
|
||||||
RectToLock.left-=2;
|
|
||||||
if ((RectToLock.bottom - RectToLock.top) > 4)
|
|
||||||
RectToLock.bottom--;
|
|
||||||
if ((RectToLock.right - RectToLock.left) > 4)
|
|
||||||
RectToLock.left++;
|
|
||||||
ResetAPIState(); // Reset any game specific settings
|
|
||||||
hr = D3D::dev->SetDepthStencilSurface(NULL);
|
|
||||||
hr = D3D::dev->SetRenderTarget(0, RBuffer);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("unable to set pixel render buffer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = 4;
|
|
||||||
vp.Height = 4;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
hr = D3D::dev->SetViewport(&vp);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("unable to set pixel viewport");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
float colmat[16] = {0.0f};
|
|
||||||
float fConstAdd[4] = {0.0f};
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = 1.0f;
|
|
||||||
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
|
||||||
EFBRectangle source_rect;
|
|
||||||
LPDIRECT3DTEXTURE9 read_texture = FramebufferManager::GetEFBDepthTexture(source_rect);
|
|
||||||
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(
|
|
||||||
read_texture,
|
|
||||||
&RectToLock,
|
|
||||||
Renderer::GetFullTargetWidth(),
|
|
||||||
Renderer::GetFullTargetHeight(),
|
|
||||||
4, 4,
|
|
||||||
(BufferFormat == FOURCC_RAWZ) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(0));
|
|
||||||
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
||||||
|
|
||||||
hr = D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
hr = D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
RestoreAPIState();
|
|
||||||
RectToLock.bottom = 4;
|
|
||||||
RectToLock.left = 0;
|
|
||||||
RectToLock.right = 4;
|
|
||||||
RectToLock.top = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr = D3D::dev->StretchRect(pBuffer, &RectToLock, RBuffer, NULL, D3DTEXF_NONE);
|
|
||||||
//change the rect to lock the entire one pixel buffer
|
|
||||||
RectToLock.bottom = 1;
|
|
||||||
RectToLock.left = 0;
|
|
||||||
RectToLock.right = 1;
|
|
||||||
RectToLock.top = 0;
|
|
||||||
}
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("Unable to stretch data to buffer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Retrieve the pixel data to the local memory buffer
|
|
||||||
D3D::dev->GetRenderTargetData(RBuffer, pOffScreenBuffer);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
PanicAlert("Unable to copy data to mem buffer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The surface is good.. lock it
|
|
||||||
if ((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK)
|
|
||||||
{
|
|
||||||
PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PEEK_Z:
|
|
||||||
{
|
|
||||||
switch (ReadBufferFormat)
|
|
||||||
{
|
|
||||||
case D3DFMT_R32F:
|
|
||||||
val = ((float*)drect.pBits)[6];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
float ffrac = 1.0f/255.0f;
|
|
||||||
z = ((u32*)drect.pBits)[6];
|
|
||||||
val = ((float)((z>>16) & 0xFF)) * ffrac;
|
|
||||||
ffrac*= 1 / 255.0f;
|
|
||||||
val += ((float)((z>>8) & 0xFF)) * ffrac;
|
|
||||||
ffrac*= 1 / 255.0f;
|
|
||||||
val += ((float)(z & 0xFF)) * ffrac;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
z = ((u32)(val * 0xffffff));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PEEK_COLOR:
|
|
||||||
z = ((u32 *)drect.pBits)[0];
|
|
||||||
break;
|
|
||||||
case POKE_COLOR:
|
|
||||||
|
|
||||||
// TODO: Implement POKE_Z and POKE_COLOR
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pOffScreenBuffer->UnlockRect();
|
|
||||||
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from VertexShaderManager
|
|
||||||
void Renderer::UpdateViewport()
|
|
||||||
{
|
|
||||||
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
|
|
||||||
// [0] = width/2
|
|
||||||
// [1] = height/2
|
|
||||||
// [2] = 16777215 * (farz - nearz)
|
|
||||||
// [3] = xorig + width/2 + 342
|
|
||||||
// [4] = yorig + height/2 + 342
|
|
||||||
// [5] = 16777215 * farz
|
|
||||||
const int old_fulltarget_w = s_Fulltarget_width;
|
|
||||||
const int old_fulltarget_h = s_Fulltarget_height;
|
|
||||||
|
|
||||||
int scissorXOff = bpmem.scissorOffset.x * 2;
|
|
||||||
int scissorYOff = bpmem.scissorOffset.y * 2;
|
|
||||||
|
|
||||||
float MValueX = Renderer::GetTargetScaleX();
|
|
||||||
float MValueY = Renderer::GetTargetScaleY();
|
|
||||||
|
|
||||||
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
int X = (int)(ceil(xfregs.rawViewport[3] - xfregs.rawViewport[0] - (scissorXOff)) * MValueX) + Xstride;
|
|
||||||
int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride;
|
|
||||||
int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX);
|
|
||||||
int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY);
|
|
||||||
if (Width < 0)
|
|
||||||
{
|
|
||||||
X += Width;
|
|
||||||
Width*=-1;
|
|
||||||
}
|
|
||||||
if (Height < 0)
|
|
||||||
{
|
|
||||||
Y += Height;
|
|
||||||
Height *= -1;
|
|
||||||
}
|
|
||||||
bool sizeChanged = false;
|
|
||||||
if (X < 0)
|
|
||||||
{
|
|
||||||
s_Fulltarget_width -= 2 * X;
|
|
||||||
X = 0;
|
|
||||||
sizeChanged=true;
|
|
||||||
}
|
|
||||||
if (Y < 0)
|
|
||||||
{
|
|
||||||
s_Fulltarget_height -= 2 * Y;
|
|
||||||
Y = 0;
|
|
||||||
sizeChanged = true;
|
|
||||||
}
|
|
||||||
if (!IS_AMD)
|
|
||||||
{
|
|
||||||
if(X + Width > s_Fulltarget_width)
|
|
||||||
{
|
|
||||||
s_Fulltarget_width += (X + Width - s_Fulltarget_width) * 2;
|
|
||||||
sizeChanged = true;
|
|
||||||
}
|
|
||||||
if(Y + Height > s_Fulltarget_height)
|
|
||||||
{
|
|
||||||
s_Fulltarget_height += (Y + Height - s_Fulltarget_height) * 2;
|
|
||||||
sizeChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sizeChanged)
|
|
||||||
{
|
|
||||||
D3DCAPS9 caps = D3D::GetCaps();
|
|
||||||
// Make sure that the requested size is actually supported by the GFX driver
|
|
||||||
if (s_Fulltarget_width > caps.MaxTextureWidth || s_Fulltarget_height > caps.MaxTextureHeight)
|
|
||||||
{
|
|
||||||
// Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least
|
|
||||||
ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", s_Fulltarget_width, s_Fulltarget_height, old_fulltarget_w, old_fulltarget_h);
|
|
||||||
|
|
||||||
// Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors
|
|
||||||
X *= old_fulltarget_w / s_Fulltarget_width;
|
|
||||||
Y *= old_fulltarget_h / s_Fulltarget_height;
|
|
||||||
Width *= old_fulltarget_w / s_Fulltarget_width;
|
|
||||||
Height *= old_fulltarget_h / s_Fulltarget_height;
|
|
||||||
|
|
||||||
s_Fulltarget_width = old_fulltarget_w;
|
|
||||||
s_Fulltarget_height = old_fulltarget_h;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
|
|
||||||
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
g_framebuffer_manager = new FramebufferManager();
|
|
||||||
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vp.X = X;
|
|
||||||
vp.Y = Y;
|
|
||||||
vp.Width = Width;
|
|
||||||
vp.Height = Height;
|
|
||||||
|
|
||||||
// Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work
|
|
||||||
vp.MinZ = 0.0f; // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
|
|
||||||
vp.MaxZ = 1.0f; // xfregs.rawViewport[5] / 16777216.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
|
|
||||||
{
|
|
||||||
// Update the view port for clearing the picture
|
|
||||||
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = targetRc.left;
|
|
||||||
vp.Y = targetRc.top;
|
|
||||||
vp.Width = targetRc.GetWidth();
|
|
||||||
vp.Height = targetRc.GetHeight();
|
|
||||||
vp.MinZ = 0.0;
|
|
||||||
vp.MaxZ = 1.0;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
|
|
||||||
// Always set the scissor in case it was set by the game and has not been reset
|
|
||||||
RECT sicr;
|
|
||||||
sicr.left = targetRc.left;
|
|
||||||
sicr.top = targetRc.top;
|
|
||||||
sicr.right = targetRc.right;
|
|
||||||
sicr.bottom = targetRc.bottom;
|
|
||||||
D3D::dev->SetScissorRect(&sicr);
|
|
||||||
D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
||||||
if (zEnable)
|
|
||||||
D3D::ChangeRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
|
|
||||||
D3D::drawClearQuad(color, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader());
|
|
||||||
if (zEnable)
|
|
||||||
D3D::RefreshRenderState(D3DRS_ZFUNC);
|
|
||||||
D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE);
|
|
||||||
UpdateViewport();
|
|
||||||
SetScissorRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.logicopenable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (bpmem.blendmode.subtract && bpmem.blendmode.blendenable)
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
||||||
D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
|
|
||||||
D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[1]);
|
|
||||||
D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)));
|
|
||||||
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)))
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
|
||||||
D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]);
|
|
||||||
D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[bpmem.blendmode.dstfactor]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::ResetAPIState()
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
|
||||||
D3D::SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
||||||
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
|
||||||
D3D::SetRenderState(D3DRS_ZENABLE, FALSE);
|
|
||||||
D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
|
||||||
DWORD color_mask = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
|
|
||||||
D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RestoreAPIState()
|
|
||||||
{
|
|
||||||
// Gets us back into a more game-like state.
|
|
||||||
D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
|
||||||
UpdateViewport();
|
|
||||||
SetScissorRect();
|
|
||||||
if (bpmem.zmode.testenable)
|
|
||||||
D3D::SetRenderState(D3DRS_ZENABLE, TRUE);
|
|
||||||
if (bpmem.zmode.updateenable)
|
|
||||||
D3D::SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
|
|
||||||
SetColorMask();
|
|
||||||
SetLogicOpMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
|
||||||
{
|
|
||||||
if (bpmem.zmode.testenable)
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_ZENABLE, TRUE);
|
|
||||||
D3D::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable);
|
|
||||||
D3D::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_ZENABLE, FALSE);
|
|
||||||
D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); // ??
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetLogicOpMode()
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
|
||||||
D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]);
|
|
||||||
D3D::SetRenderState(D3DRS_SRCBLEND, d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]);
|
|
||||||
D3D::SetRenderState(D3DRS_DESTBLEND, d3dLogicOpDestFactors[bpmem.blendmode.logicmode]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetBlendMode(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDitherMode()
|
|
||||||
{
|
|
||||||
D3D::SetRenderState(D3DRS_DITHERENABLE, bpmem.blendmode.dither);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetLineWidth()
|
|
||||||
{
|
|
||||||
// We can't change line width in D3D unless we use ID3DXLine
|
|
||||||
float fratio = xfregs.rawViewport[0] != 0 ? Renderer::GetTargetScaleX() : 1.0f;
|
|
||||||
float psize = bpmem.lineptwidth.linesize * fratio / 6.0f;
|
|
||||||
D3D::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetSamplerState(int stage, int texindex)
|
|
||||||
{
|
|
||||||
const FourTexUnits &tex = bpmem.tex[texindex];
|
|
||||||
const TexMode0 &tm0 = tex.texMode0[stage];
|
|
||||||
const TexMode1 &tm1 = tex.texMode1[stage];
|
|
||||||
|
|
||||||
D3DTEXTUREFILTERTYPE min, mag, mip;
|
|
||||||
if (g_ActiveConfig.bForceFiltering)
|
|
||||||
{
|
|
||||||
min = mag = mip = D3DTEXF_LINEAR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
|
|
||||||
mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
|
|
||||||
mip = (tm0.min_filter == 8) ? D3DTEXF_NONE : d3dMipFilters[tm0.min_filter & 3];
|
|
||||||
if((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0))
|
|
||||||
mip = D3DTEXF_NONE;
|
|
||||||
}
|
|
||||||
if (texindex)
|
|
||||||
stage += 4;
|
|
||||||
|
|
||||||
if (mag == D3DTEXF_LINEAR && min == D3DTEXF_LINEAR && g_ActiveConfig.iMaxAnisotropy > 1)
|
|
||||||
{
|
|
||||||
min = D3DTEXF_ANISOTROPIC;
|
|
||||||
}
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MINFILTER, min);
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MAGFILTER, mag);
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MIPFILTER, mip);
|
|
||||||
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]);
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]);
|
|
||||||
//float SuperSampleCoeficient = (s_LastAA < 3)? s_LastAA + 1 : s_LastAA - 1;// uncoment this changes to conserve detail when incresing ssaa level
|
|
||||||
float lodbias = (tm0.lod_bias / 32.0f);// + (s_LastAA)?(log(SuperSampleCoeficient) / log(2.0f)):0;
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias);
|
|
||||||
D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect)
|
|
||||||
{
|
|
||||||
D3D::dev->SetDepthStencilSurface(NULL);
|
|
||||||
D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface());
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = s_backbuffer_width;
|
|
||||||
vp.Height = s_backbuffer_height;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
|
|
||||||
|
|
||||||
int X = dst_rect.left;
|
|
||||||
int Y = dst_rect.top;
|
|
||||||
int Width = dst_rect.right - dst_rect.left;
|
|
||||||
int Height = dst_rect.bottom - dst_rect.top;
|
|
||||||
|
|
||||||
if (X < 0) X = 0;
|
|
||||||
if (Y < 0) Y = 0;
|
|
||||||
if (X > s_backbuffer_width) X = s_backbuffer_width;
|
|
||||||
if (Y > s_backbuffer_height) Y = s_backbuffer_height;
|
|
||||||
if (Width < 0) Width = 0;
|
|
||||||
if (Height < 0) Height = 0;
|
|
||||||
if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X;
|
|
||||||
if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y;
|
|
||||||
vp.X = X;
|
|
||||||
vp.Y = Y;
|
|
||||||
vp.Width = Width;
|
|
||||||
vp.Height = Height;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc)
|
|
||||||
{
|
|
||||||
// TODO: this is lame here
|
|
||||||
TargetRectangle dst_rect;
|
|
||||||
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect);
|
|
||||||
|
|
||||||
const int Width = dst_rect.right - dst_rect.left;
|
|
||||||
const int Height = dst_rect.bottom - dst_rect.top;
|
|
||||||
|
|
||||||
if (xfbSource)
|
|
||||||
{
|
|
||||||
const LPDIRECT3DTEXTURE9 tex = ((XFBSource*)xfbSource)->texture;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
//D3D::drawShadedTexSubQuad(tex, &sourceRc, xfbSource->texWidth,
|
|
||||||
// xfbSource->texHeight, &drawRc, Width, Height, PixelShaderCache::GetColorCopyProgram(0),
|
|
||||||
// VertexShaderCache::GetSimpleVertexShader(0));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const LPDIRECT3DTEXTURE9 tex = FramebufferManager::GetEFBColorTexture(rc);
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(tex, sourceRc.AsRECT(), Renderer::GetFullTargetWidth(),
|
|
||||||
Renderer::GetFullTargetHeight(), Width, Height,
|
|
||||||
PixelShaderCache::GetColorCopyProgram(g_Config.iMultisampleMode),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(g_Config.iMultisampleMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: good here?
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER);
|
|
||||||
|
|
||||||
// TODO: this is for overlay text i think, move it elsewhere
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = s_backbuffer_width;
|
|
||||||
vp.Height = s_backbuffer_height;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::EndFrame()
|
|
||||||
{
|
|
||||||
D3D::EndFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Present()
|
|
||||||
{
|
|
||||||
D3D::Present();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::GetBackBufferSize(int* w, int* h)
|
|
||||||
{
|
|
||||||
*w = D3D::GetBackBufferWidth();
|
|
||||||
*h = D3D::GetBackBufferHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RecreateFramebufferManger()
|
|
||||||
{
|
|
||||||
// TODO: these ok here?
|
|
||||||
D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface());
|
|
||||||
SetupDeviceObjects();
|
|
||||||
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
g_framebuffer_manager = new FramebufferManager;
|
|
||||||
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::BeginFrame()
|
|
||||||
{
|
|
||||||
D3D::BeginFrame();
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MathUtil.h"
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
class Renderer : public ::RendererBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Renderer();
|
|
||||||
~Renderer();
|
|
||||||
|
|
||||||
void ResetAPIState();
|
|
||||||
void RestoreAPIState();
|
|
||||||
|
|
||||||
static void SetupDeviceObjects();
|
|
||||||
static void TeardownDeviceObjects();
|
|
||||||
|
|
||||||
void SetColorMask();
|
|
||||||
void SetBlendMode(bool forceUpdate);
|
|
||||||
bool SetScissorRect();
|
|
||||||
|
|
||||||
void SetGenerationMode();
|
|
||||||
void SetDepthMode();
|
|
||||||
void SetLogicOpMode();
|
|
||||||
void SetSamplerState(int stage,int texindex);
|
|
||||||
void SetDitherMode();
|
|
||||||
void SetLineWidth();
|
|
||||||
|
|
||||||
u32 AccessEFB(EFBAccessType type, int x, int y);
|
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
|
||||||
void UpdateViewport();
|
|
||||||
|
|
||||||
// virtual funcs used by RendererBase::Swap
|
|
||||||
void PrepareXFBCopy(const TargetRectangle &dst_rect);
|
|
||||||
void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc);
|
|
||||||
void EndFrame();
|
|
||||||
void Present();
|
|
||||||
bool CheckForResize();
|
|
||||||
void GetBackBufferSize(int* w, int* h);
|
|
||||||
void RecreateFramebufferManger();
|
|
||||||
void BeginFrame();
|
|
||||||
|
|
||||||
void Swap(u32, FieldType, u32, u32, const EFBRectangle&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool IS_AMD;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,207 +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 <d3dx9.h>
|
|
||||||
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "Hash.h"
|
|
||||||
|
|
||||||
#include "CommonPaths.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DTexture.h"
|
|
||||||
#include "DX9_D3DUtil.h"
|
|
||||||
#include "DX9_FramebufferManager.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
|
|
||||||
#include "TextureDecoder.h"
|
|
||||||
#include "DX9_TextureCache.h"
|
|
||||||
#include "HiresTextures.h"
|
|
||||||
#include "DX9_TextureConverter.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
//#include "debugger/debugger.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
TextureCache::TCacheEntry::TCacheEntry(LPDIRECT3DTEXTURE9 _texture)
|
|
||||||
: texture(_texture), isDynamic(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntry::~TCacheEntry()
|
|
||||||
{
|
|
||||||
texture->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int level)
|
|
||||||
{
|
|
||||||
D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
|
||||||
texture->GetSurfaceLevel(0, &Rendersurf);
|
|
||||||
D3D::dev->SetDepthStencilSurface(NULL);
|
|
||||||
D3D::dev->SetRenderTarget(0, Rendersurf);
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = Scaledw;
|
|
||||||
vp.Height = Scaledh;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
RECT destrect;
|
|
||||||
destrect.bottom = Scaledh;
|
|
||||||
destrect.left = 0;
|
|
||||||
destrect.right = Scaledw;
|
|
||||||
destrect.top = 0;
|
|
||||||
|
|
||||||
const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat
|
|
||||||
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
|
||||||
TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect);
|
|
||||||
RECT sourcerect;
|
|
||||||
sourcerect.bottom = targetSource.bottom;
|
|
||||||
sourcerect.left = targetSource.left;
|
|
||||||
sourcerect.right = targetSource.right;
|
|
||||||
sourcerect.top = targetSource.top;
|
|
||||||
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
if (bScaleByHalf || g_ActiveConfig.iMultisampleMode)
|
|
||||||
{
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ?
|
|
||||||
FramebufferManager::GetEFBDepthTexture(source_rect) :
|
|
||||||
FramebufferManager::GetEFBColorTexture(source_rect);
|
|
||||||
|
|
||||||
D3DFORMAT bformat = FramebufferManager::GetEFBDepthRTSurfaceFormat();
|
|
||||||
int SSAAMode = g_ActiveConfig.iMultisampleMode;
|
|
||||||
|
|
||||||
D3D::drawShadedTexQuad(read_texture, &sourcerect,
|
|
||||||
Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(),
|
|
||||||
Scaledw, Scaledh,
|
|
||||||
((bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8) && bFromZBuffer) ?
|
|
||||||
PixelShaderCache::GetDepthMatrixProgram(SSAAMode) :
|
|
||||||
PixelShaderCache::GetColorMatrixProgram(SSAAMode),
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(SSAAMode));
|
|
||||||
|
|
||||||
Rendersurf->Release();
|
|
||||||
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER);
|
|
||||||
D3D::SetTexture(0,NULL);
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
|
||||||
{
|
|
||||||
D3D::SetTexture(stage, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt)
|
|
||||||
{
|
|
||||||
D3DFORMAT d3d_fmt;
|
|
||||||
bool swap_r_b = false;
|
|
||||||
|
|
||||||
switch (pcfmt)
|
|
||||||
{
|
|
||||||
case PC_TEX_FMT_BGRA32:
|
|
||||||
d3d_fmt = D3DFMT_A8R8G8B8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_RGBA32:
|
|
||||||
d3d_fmt = D3DFMT_A8R8G8B8;
|
|
||||||
swap_r_b = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_RGB565:
|
|
||||||
d3d_fmt = D3DFMT_R5G6B5;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_IA4_AS_IA8:
|
|
||||||
d3d_fmt = D3DFMT_A8L8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_I8:
|
|
||||||
case PC_TEX_FMT_I4_AS_I8:
|
|
||||||
// A hack which means the format is a packed
|
|
||||||
// 8-bit intensity texture. It is unpacked
|
|
||||||
// to A8L8 in D3DTexture.cpp
|
|
||||||
d3d_fmt = D3DFMT_A8P8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_IA8:
|
|
||||||
d3d_fmt = D3DFMT_A8L8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_DXT1:
|
|
||||||
d3d_fmt = D3DFMT_DXT1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TCacheEntry* entry = new TCacheEntry(D3D::CreateTexture2D(temp, width, height, expanded_width, d3d_fmt, swap_r_b, tex_levels));
|
|
||||||
entry->swap_r_b = swap_r_b;
|
|
||||||
entry->d3d_fmt = d3d_fmt;
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h)
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 texture;
|
|
||||||
D3D::dev->CreateTexture(scaled_tex_w, scaled_tex_h, 1, D3DUSAGE_RENDERTARGET,
|
|
||||||
D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, 0);
|
|
||||||
|
|
||||||
return new TCacheEntry(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,67 +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 _TEXTURECACHE_H
|
|
||||||
#define _TEXTURECACHE_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
|
|
||||||
#include "../TextureCache.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
class TextureCache : public TextureCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct TCacheEntry : TCacheEntryBase
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 texture;
|
|
||||||
|
|
||||||
D3DFORMAT d3d_fmt;
|
|
||||||
bool swap_r_b;
|
|
||||||
bool isDynamic; // mofified from cpu
|
|
||||||
|
|
||||||
TCacheEntry(LPDIRECT3DTEXTURE9 _texture);
|
|
||||||
~TCacheEntry();
|
|
||||||
|
|
||||||
void Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int levels);
|
|
||||||
|
|
||||||
void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect);
|
|
||||||
|
|
||||||
void Bind(unsigned int stage);
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,560 +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/
|
|
||||||
|
|
||||||
// Fast image conversion using OpenGL shaders.
|
|
||||||
// This kind of stuff would be a LOT nicer with OpenCL.
|
|
||||||
|
|
||||||
#include "DX9_TextureConverter.h"
|
|
||||||
#include "TextureConversionShader.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "DX9_FramebufferManager.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "DX9_Render.h"
|
|
||||||
#include "DX9_TextureCache.h"
|
|
||||||
#include "Math.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace TextureConverter
|
|
||||||
{
|
|
||||||
|
|
||||||
struct TransformBuffer
|
|
||||||
{
|
|
||||||
LPDIRECT3DTEXTURE9 FBTexture;
|
|
||||||
LPDIRECT3DSURFACE9 RenderSurface;
|
|
||||||
LPDIRECT3DSURFACE9 ReadSurface;
|
|
||||||
int Width;
|
|
||||||
int Height;
|
|
||||||
};
|
|
||||||
const u32 NUM_TRANSFORM_BUFFERS = 16;
|
|
||||||
static TransformBuffer TrnBuffers[NUM_TRANSFORM_BUFFERS];
|
|
||||||
static u32 WorkingBuffers = 0;
|
|
||||||
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_rgbToYuyvProgram = NULL;
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_yuyvToRgbProgram = NULL;
|
|
||||||
|
|
||||||
// Not all slots are taken - but who cares.
|
|
||||||
const u32 NUM_ENCODING_PROGRAMS = 64;
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
|
||||||
|
|
||||||
void CreateRgbToYuyvProgram()
|
|
||||||
{
|
|
||||||
// Output is BGRA because that is slightly faster than RGBA.
|
|
||||||
char* FProgram = new char[2048];
|
|
||||||
sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n"
|
|
||||||
"uniform float4 textureDims : register(c%d);\n"
|
|
||||||
"uniform sampler 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)/ blkDims.z, uv0.y / blkDims.w);\n"
|
|
||||||
" float3 c0 = tex2D(samp0, uv0.xy / blkDims.zw).rgb;\n"
|
|
||||||
" float3 c1 = tex2D(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",C_COLORMATRIX,C_COLORMATRIX+1);
|
|
||||||
|
|
||||||
s_rgbToYuyvProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram));
|
|
||||||
if (!s_rgbToYuyvProgram) {
|
|
||||||
ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program");
|
|
||||||
}
|
|
||||||
delete [] FProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateYuyvToRgbProgram()
|
|
||||||
{
|
|
||||||
char* FProgram = new char[2048];
|
|
||||||
sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n"
|
|
||||||
"uniform float4 textureDims : register(c%d);\n"
|
|
||||||
"uniform sampler samp0 : register(s0);\n"
|
|
||||||
"void main(\n"
|
|
||||||
" out float4 ocol0 : COLOR0,\n"
|
|
||||||
" in float2 uv0 : TEXCOORD0)\n"
|
|
||||||
"{\n"
|
|
||||||
" float4 c0 = tex2D(samp0, uv0 / blkDims.zw).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",C_COLORMATRIX,C_COLORMATRIX+1);
|
|
||||||
s_yuyvToRgbProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram));
|
|
||||||
if (!s_yuyvToRgbProgram) {
|
|
||||||
ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program");
|
|
||||||
}
|
|
||||||
delete [] FProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 GetOrCreateEncodingShader(u32 format)
|
|
||||||
{
|
|
||||||
if (format > NUM_ENCODING_PROGRAMS)
|
|
||||||
{
|
|
||||||
PanicAlert("Unknown texture copy format: 0x%x\n", format);
|
|
||||||
return s_encodingPrograms[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s_encodingPrograms[format])
|
|
||||||
{
|
|
||||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_D3D9);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) {
|
|
||||||
static int counter = 0;
|
|
||||||
char szTemp[MAX_PATH];
|
|
||||||
sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++);
|
|
||||||
|
|
||||||
SaveData(szTemp, shader);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
s_encodingPrograms[format] = D3D::CompileAndCreatePixelShader(shader, (int)strlen(shader));
|
|
||||||
if (!s_encodingPrograms[format]) {
|
|
||||||
ERROR_LOG(VIDEO, "Failed to create encoding fragment program");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s_encodingPrograms[format];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++)
|
|
||||||
{
|
|
||||||
s_encodingPrograms[i] = NULL;
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++)
|
|
||||||
{
|
|
||||||
TrnBuffers[i].FBTexture = NULL;
|
|
||||||
TrnBuffers[i].RenderSurface = NULL;
|
|
||||||
TrnBuffers[i].ReadSurface = NULL;
|
|
||||||
TrnBuffers[i].Width = 0;
|
|
||||||
TrnBuffers[i].Height = 0;
|
|
||||||
}
|
|
||||||
CreateRgbToYuyvProgram();
|
|
||||||
CreateYuyvToRgbProgram();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
if(s_rgbToYuyvProgram)
|
|
||||||
s_rgbToYuyvProgram->Release();
|
|
||||||
s_rgbToYuyvProgram = NULL;
|
|
||||||
if(s_yuyvToRgbProgram)
|
|
||||||
s_yuyvToRgbProgram->Release();
|
|
||||||
s_yuyvToRgbProgram=NULL;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++)
|
|
||||||
{
|
|
||||||
if(s_encodingPrograms[i])
|
|
||||||
s_encodingPrograms[i]->Release();
|
|
||||||
s_encodingPrograms[i] = NULL;
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++)
|
|
||||||
{
|
|
||||||
if(TrnBuffers[i].RenderSurface != NULL)
|
|
||||||
TrnBuffers[i].RenderSurface->Release();
|
|
||||||
TrnBuffers[i].RenderSurface = NULL;
|
|
||||||
|
|
||||||
if(TrnBuffers[i].ReadSurface != NULL)
|
|
||||||
TrnBuffers[i].ReadSurface->Release();
|
|
||||||
TrnBuffers[i].ReadSurface = NULL;
|
|
||||||
|
|
||||||
if(TrnBuffers[i].FBTexture != NULL)
|
|
||||||
TrnBuffers[i].FBTexture->Release();
|
|
||||||
TrnBuffers[i].FBTexture = NULL;
|
|
||||||
|
|
||||||
TrnBuffers[i].Width = 0;
|
|
||||||
TrnBuffers[i].Height = 0;
|
|
||||||
}
|
|
||||||
WorkingBuffers = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,
|
|
||||||
u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
u32 index =0;
|
|
||||||
while(index < WorkingBuffers && (TrnBuffers[index].Width != dstWidth || TrnBuffers[index].Height != dstHeight))
|
|
||||||
index++;
|
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 s_texConvReadSurface = NULL;
|
|
||||||
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
|
||||||
|
|
||||||
if (index >= WorkingBuffers)
|
|
||||||
{
|
|
||||||
if (WorkingBuffers < NUM_TRANSFORM_BUFFERS)
|
|
||||||
WorkingBuffers++;
|
|
||||||
if (index >= WorkingBuffers)
|
|
||||||
index--;
|
|
||||||
if (TrnBuffers[index].RenderSurface != NULL)
|
|
||||||
{
|
|
||||||
TrnBuffers[index].RenderSurface->Release();
|
|
||||||
TrnBuffers[index].RenderSurface = NULL;
|
|
||||||
}
|
|
||||||
if (TrnBuffers[index].ReadSurface != NULL)
|
|
||||||
{
|
|
||||||
TrnBuffers[index].ReadSurface->Release();
|
|
||||||
TrnBuffers[index].ReadSurface = NULL;
|
|
||||||
}
|
|
||||||
if (TrnBuffers[index].FBTexture != NULL)
|
|
||||||
{
|
|
||||||
TrnBuffers[index].FBTexture->Release();
|
|
||||||
TrnBuffers[index].FBTexture = NULL;
|
|
||||||
}
|
|
||||||
TrnBuffers[index].Width = dstWidth;
|
|
||||||
TrnBuffers[index].Height = dstHeight;
|
|
||||||
D3D::dev->CreateTexture(dstWidth, dstHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
|
||||||
D3DPOOL_DEFAULT, &TrnBuffers[index].FBTexture, NULL);
|
|
||||||
TrnBuffers[index].FBTexture->GetSurfaceLevel(0,&TrnBuffers[index].RenderSurface);
|
|
||||||
D3D::dev->CreateOffscreenPlainSurface(dstWidth, dstHeight, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &TrnBuffers[index].ReadSurface, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
s_texConvReadSurface = TrnBuffers[index].ReadSurface;
|
|
||||||
Rendersurf = TrnBuffers[index].RenderSurface;
|
|
||||||
|
|
||||||
hr = D3D::dev->SetDepthStencilSurface(NULL);
|
|
||||||
hr = D3D::dev->SetRenderTarget(0, Rendersurf);
|
|
||||||
|
|
||||||
if (linearFilter)
|
|
||||||
{
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = dstWidth;
|
|
||||||
vp.Height = dstHeight;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
hr = D3D::dev->SetViewport(&vp);
|
|
||||||
RECT SrcRect;
|
|
||||||
SrcRect.top = sourceRc.top;
|
|
||||||
SrcRect.left = sourceRc.left;
|
|
||||||
SrcRect.right = sourceRc.right;
|
|
||||||
SrcRect.bottom = sourceRc.bottom;
|
|
||||||
RECT DstRect;
|
|
||||||
DstRect.top = 0;
|
|
||||||
DstRect.left = 0;
|
|
||||||
DstRect.right = dstWidth;
|
|
||||||
DstRect.bottom = dstHeight;
|
|
||||||
|
|
||||||
|
|
||||||
// Draw...
|
|
||||||
D3D::drawShadedTexQuad(srcTexture,&SrcRect,1,1,dstWidth,dstHeight,shader,VertexShaderCache::GetSimpleVertexShader(0));
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
||||||
// .. and then readback the results.
|
|
||||||
// TODO: make this less slow.
|
|
||||||
|
|
||||||
D3DLOCKED_RECT drect;
|
|
||||||
|
|
||||||
|
|
||||||
hr = D3D::dev->GetRenderTargetData(Rendersurf,s_texConvReadSurface);
|
|
||||||
if((hr = s_texConvReadSurface->LockRect(&drect, &DstRect, D3DLOCK_READONLY)) != D3D_OK)
|
|
||||||
{
|
|
||||||
PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" :
|
|
||||||
hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t");
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int writeStride = bpmem.copyMipMapStrideChannels * 32;
|
|
||||||
|
|
||||||
if (writeStride != readStride && toTexture)
|
|
||||||
{
|
|
||||||
// writing to a texture of a different size
|
|
||||||
|
|
||||||
int readHeight = readStride / dstWidth;
|
|
||||||
|
|
||||||
int readStart = 0;
|
|
||||||
int readLoops = dstHeight / (readHeight/4); // 4 bytes per pixel
|
|
||||||
u8 *Source = (u8*)drect.pBits;
|
|
||||||
for (int i = 0; i < readLoops; i++)
|
|
||||||
{
|
|
||||||
int readDist = dstWidth*readHeight;
|
|
||||||
memcpy(destAddr,Source,readDist);
|
|
||||||
Source += readDist;
|
|
||||||
destAddr += writeStride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memcpy(destAddr,drect.pBits,dstWidth*dstHeight*4);// 4 bytes per pixel
|
|
||||||
|
|
||||||
hr = s_texConvReadSurface->UnlockRect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
|
||||||
{
|
|
||||||
u32 format = copyfmt;
|
|
||||||
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
format |= _GX_TF_ZTF;
|
|
||||||
if (copyfmt == 11)
|
|
||||||
format = GX_TF_Z16;
|
|
||||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format);
|
|
||||||
if (!texconv_shader)
|
|
||||||
return;
|
|
||||||
|
|
||||||
u8 *dest_ptr = Memory_GetPtr(address);
|
|
||||||
|
|
||||||
LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ?
|
|
||||||
FramebufferManager::GetEFBDepthTexture(source) :
|
|
||||||
FramebufferManager::GetEFBColorTexture(source);
|
|
||||||
int width = (source.right - source.left) >> bScaleByHalf;
|
|
||||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
|
||||||
|
|
||||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
|
||||||
|
|
||||||
// Invalidate any existing texture covering this memory range.
|
|
||||||
// TODO - don't delete the texture if it already exists, just replace the contents.
|
|
||||||
TextureCache::InvalidateRange(address, size_in_bytes);
|
|
||||||
|
|
||||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
|
||||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
|
||||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
|
||||||
|
|
||||||
// only copy on cache line boundaries
|
|
||||||
// extra pixels are copied but not displayed in the resulting texture
|
|
||||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
|
||||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
|
||||||
|
|
||||||
float MValueX = Renderer::GetTargetScaleX();
|
|
||||||
float MValueY = Renderer::GetTargetScaleY();
|
|
||||||
|
|
||||||
float Xstride = (float)((Renderer::GetFullTargetWidth() - Renderer::GetTargetWidth()) / 2);
|
|
||||||
float Ystride = (float)((Renderer::GetFullTargetHeight() - Renderer::GetTargetHeight()) / 2);
|
|
||||||
|
|
||||||
float sampleStride = bScaleByHalf?2.0f:1.0f;
|
|
||||||
|
|
||||||
TextureConversionShader::SetShaderParameters(
|
|
||||||
(float)expandedWidth,
|
|
||||||
expandedHeight * MValueY,
|
|
||||||
source.left * MValueX + Xstride ,
|
|
||||||
source.top * MValueY + Ystride,
|
|
||||||
sampleStride * MValueX,
|
|
||||||
sampleStride * MValueY,
|
|
||||||
(float)Renderer::GetFullTargetWidth(),
|
|
||||||
(float)Renderer::GetFullTargetHeight());
|
|
||||||
|
|
||||||
TargetRectangle scaledSource;
|
|
||||||
scaledSource.top = 0;
|
|
||||||
scaledSource.bottom = expandedHeight;
|
|
||||||
scaledSource.left = 0;
|
|
||||||
scaledSource.right = expandedWidth / samples;
|
|
||||||
int cacheBytes = 32;
|
|
||||||
if ((format & 0x0f) == 6)
|
|
||||||
cacheBytes = 64;
|
|
||||||
|
|
||||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
|
||||||
g_renderer->ResetAPIState();
|
|
||||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0);
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
|
||||||
{
|
|
||||||
u32 format = copyfmt;
|
|
||||||
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
format |= _GX_TF_ZTF;
|
|
||||||
if (copyfmt == 11)
|
|
||||||
format = GX_TF_Z16;
|
|
||||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format);
|
|
||||||
if (!texconv_shader)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
u8 *dest_ptr = Memory_GetPtr(address);
|
|
||||||
|
|
||||||
int width = (source.right - source.left) >> bScaleByHalf;
|
|
||||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
|
||||||
|
|
||||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
|
||||||
|
|
||||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
|
||||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
|
||||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
|
||||||
|
|
||||||
// only copy on cache line boundaries
|
|
||||||
// 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.0f:1.0f;
|
|
||||||
|
|
||||||
TextureConversionShader::SetShaderParameters(
|
|
||||||
(float)expandedWidth,
|
|
||||||
expandedHeight * MValueY,
|
|
||||||
source.left * MValueX + Xstride ,
|
|
||||||
source.top * MValueY + Ystride,
|
|
||||||
sampleStride * MValueX,
|
|
||||||
sampleStride * MValueY,
|
|
||||||
(float)SourceW,
|
|
||||||
(float)SourceH);
|
|
||||||
|
|
||||||
TargetRectangle scaledSource;
|
|
||||||
scaledSource.top = 0;
|
|
||||||
scaledSource.bottom = expandedHeight;
|
|
||||||
scaledSource.left = 0;
|
|
||||||
scaledSource.right = expandedWidth / samples;
|
|
||||||
int cacheBytes = 32;
|
|
||||||
if ((format & 0x0f) == 6)
|
|
||||||
cacheBytes = 64;
|
|
||||||
|
|
||||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
|
||||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0);
|
|
||||||
TextureCache::MakeRangeDynamic(address,size_in_bytes);
|
|
||||||
u64 Hashvalue = 0;
|
|
||||||
Hashvalue = GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
|
||||||
return Hashvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,u8* destAddr, int dstWidth, int dstHeight)
|
|
||||||
{
|
|
||||||
TextureConversionShader::SetShaderParameters(
|
|
||||||
(float)dstWidth,
|
|
||||||
(float)dstHeight,
|
|
||||||
0.0f ,
|
|
||||||
0.0f,
|
|
||||||
1.0f,
|
|
||||||
1.0f,
|
|
||||||
(float)Renderer::GetFullTargetWidth(),
|
|
||||||
(float)Renderer::GetFullTargetHeight());
|
|
||||||
g_renderer->ResetAPIState();
|
|
||||||
EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false);
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Should be scale free.
|
|
||||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture)
|
|
||||||
{
|
|
||||||
u8* srcAddr = Memory_GetPtr(xfbAddr);
|
|
||||||
if (!srcAddr)
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "Tried to decode from invalid memory address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int srcFmtWidth = srcWidth / 2;
|
|
||||||
|
|
||||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
|
||||||
LPDIRECT3DTEXTURE9 s_srcTexture = D3D::CreateTexture2D(srcAddr, srcFmtWidth, srcHeight, srcFmtWidth, D3DFMT_A8R8G8B8, false);
|
|
||||||
LPDIRECT3DSURFACE9 Rendersurf = NULL;
|
|
||||||
destTexture->GetSurfaceLevel(0,&Rendersurf);
|
|
||||||
D3D::dev->SetDepthStencilSurface(NULL);
|
|
||||||
D3D::dev->SetRenderTarget(0, Rendersurf);
|
|
||||||
|
|
||||||
D3DVIEWPORT9 vp;
|
|
||||||
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
vp.X = 0;
|
|
||||||
vp.Y = 0;
|
|
||||||
vp.Width = srcWidth;
|
|
||||||
vp.Height = srcHeight;
|
|
||||||
vp.MinZ = 0.0f;
|
|
||||||
vp.MaxZ = 1.0f;
|
|
||||||
D3D::dev->SetViewport(&vp);
|
|
||||||
RECT destrect;
|
|
||||||
destrect.bottom = srcHeight;
|
|
||||||
destrect.left = 0;
|
|
||||||
destrect.right = srcWidth;
|
|
||||||
destrect.top = 0;
|
|
||||||
|
|
||||||
RECT sourcerect;
|
|
||||||
sourcerect.bottom = srcHeight;
|
|
||||||
sourcerect.left = 0;
|
|
||||||
sourcerect.right = srcFmtWidth;
|
|
||||||
sourcerect.top = 0;
|
|
||||||
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
|
|
||||||
D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
|
|
||||||
|
|
||||||
TextureConversionShader::SetShaderParameters(
|
|
||||||
(float)srcFmtWidth,
|
|
||||||
(float)srcHeight,
|
|
||||||
0.0f ,
|
|
||||||
0.0f,
|
|
||||||
1.0f,
|
|
||||||
1.0f,
|
|
||||||
(float)srcFmtWidth,
|
|
||||||
(float)srcHeight);
|
|
||||||
D3D::drawShadedTexQuad(
|
|
||||||
s_srcTexture,
|
|
||||||
&sourcerect,
|
|
||||||
1 ,
|
|
||||||
1,
|
|
||||||
srcWidth,
|
|
||||||
srcHeight,
|
|
||||||
s_yuyvToRgbProgram,
|
|
||||||
VertexShaderCache::GetSimpleVertexShader(0));
|
|
||||||
|
|
||||||
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER);
|
|
||||||
D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER);
|
|
||||||
D3D::SetTexture(0,NULL);
|
|
||||||
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
|
||||||
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
Rendersurf->Release();
|
|
||||||
s_srcTexture->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,53 +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 _TEXTURECONVERTER_H_
|
|
||||||
#define _TEXTURECONVERTER_H_
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DTexture.h"
|
|
||||||
#include "DX9_D3DUtil.h"
|
|
||||||
#include "DX9_D3DShader.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
// Converts textures between formats
|
|
||||||
// TODO: support multiple texture formats
|
|
||||||
namespace TextureConverter
|
|
||||||
{
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
|
||||||
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
|
||||||
|
|
||||||
void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,
|
|
||||||
u8* destAddr, int dstWidth, int dstHeight);
|
|
||||||
|
|
||||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture);
|
|
||||||
|
|
||||||
u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _TEXTURECONVERTER_H_
|
|
|
@ -1,135 +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 "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "DX9_VertexManager.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "IndexGenerator.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "DX9_PixelShaderCache.h"
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
#include "NativeVertexWriter.h"
|
|
||||||
#include "DX9_TextureCache.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "XFStructs.h"
|
|
||||||
|
|
||||||
//#include "debugger/debugger.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace D3D;
|
|
||||||
|
|
||||||
// internal state for loading vertices
|
|
||||||
extern NativeVertexFormat *g_nativeVertexFmt;
|
|
||||||
|
|
||||||
inline void DumpBadShaders()
|
|
||||||
{
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string error_shaders;
|
|
||||||
error_shaders.append(VertexShaderCache::GetCurrentShaderCode());
|
|
||||||
error_shaders.append(PixelShaderCache::GetCurrentShaderCode());
|
|
||||||
char filename[512] = "bad_shader_combo_0.txt";
|
|
||||||
int which = 0;
|
|
||||||
while (File::Exists(filename))
|
|
||||||
{
|
|
||||||
which++;
|
|
||||||
sprintf(filename, "bad_shader_combo_%i.txt", which);
|
|
||||||
}
|
|
||||||
File::WriteStringToFile(true, error_shaders, filename);
|
|
||||||
PanicAlert("DrawIndexedPrimitiveUP failed. Shaders written to %s", filename);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManager::Draw(u32 stride, bool alphapass)
|
|
||||||
{
|
|
||||||
if (alphapass)
|
|
||||||
{
|
|
||||||
DWORD write = 0;
|
|
||||||
if (false == g_pixel_shader_cache->SetShader(true))
|
|
||||||
{
|
|
||||||
//DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
|
|
||||||
//goto shader_fail;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// update alpha only
|
|
||||||
D3D::ChangeRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA);
|
|
||||||
D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IndexGenerator::GetNumTriangles() > 0)
|
|
||||||
{
|
|
||||||
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
|
|
||||||
D3DPT_TRIANGLELIST,
|
|
||||||
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumTriangles(),
|
|
||||||
TIBuffer,
|
|
||||||
D3DFMT_INDEX16,
|
|
||||||
LocalVBuffer,
|
|
||||||
stride)))
|
|
||||||
{
|
|
||||||
DumpBadShaders();
|
|
||||||
}
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumLines() > 0)
|
|
||||||
{
|
|
||||||
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
|
|
||||||
D3DPT_LINELIST,
|
|
||||||
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumLines(),
|
|
||||||
LIBuffer,
|
|
||||||
D3DFMT_INDEX16,
|
|
||||||
LocalVBuffer,
|
|
||||||
stride)))
|
|
||||||
{
|
|
||||||
DumpBadShaders();
|
|
||||||
}
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumPoints() > 0)
|
|
||||||
{
|
|
||||||
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
|
|
||||||
D3DPT_POINTLIST,
|
|
||||||
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumPoints(),
|
|
||||||
PIBuffer,
|
|
||||||
D3DFMT_INDEX16,
|
|
||||||
LocalVBuffer,
|
|
||||||
stride)))
|
|
||||||
{
|
|
||||||
DumpBadShaders();
|
|
||||||
}
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphapass)
|
|
||||||
{
|
|
||||||
D3D::RefreshRenderState(D3DRS_COLORWRITEENABLE);
|
|
||||||
D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
|
@ -1,39 +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 _VERTEXMANAGER_H
|
|
||||||
#define _VERTEXMANAGER_H
|
|
||||||
|
|
||||||
#include "CPMemory.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
|
|
||||||
#include "../VertexManager.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
class VertexManager : public ::VertexManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Draw(u32 stride, bool alphapass);
|
|
||||||
|
|
||||||
NativeVertexFormat* CreateNativeVertexFormat();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,302 +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 <map>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "LinearDiskCache.h"
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "DX9_D3DShader.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "DX9_VertexShaderCache.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "XFMemory.h"
|
|
||||||
|
|
||||||
//#include "debugger/debugger.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
|
||||||
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
|
|
||||||
|
|
||||||
#define MAX_SSAA_SHADERS 3
|
|
||||||
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 SimpleVertexShader[MAX_SSAA_SHADERS];
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 ClearVertexShader;
|
|
||||||
|
|
||||||
LinearDiskCache g_vs_disk_cache;
|
|
||||||
|
|
||||||
LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetSimpleVertexShader(int level)
|
|
||||||
{
|
|
||||||
return SimpleVertexShader[level % MAX_SSAA_SHADERS];
|
|
||||||
}
|
|
||||||
|
|
||||||
LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetClearVertexShader()
|
|
||||||
{
|
|
||||||
return ClearVertexShader;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
const float f[4] = { f1, f2, f3, f4 };
|
|
||||||
D3D::dev->SetVertexShaderConstantF(const_number, f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexShaderConstantF(const_number, f, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
D3D::dev->SetVertexShaderConstantF(const_number, buf, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
D3D::dev->SetVertexShaderConstantF(const_number, f, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
class VertexShaderCacheInserter : public LinearDiskCacheReader {
|
|
||||||
public:
|
|
||||||
void Read(const u8 *key, int key_size, const u8 *value, int value_size)
|
|
||||||
{
|
|
||||||
VERTEXSHADERUID uid;
|
|
||||||
if (key_size != sizeof(uid)) {
|
|
||||||
ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memcpy(&uid, key, key_size);
|
|
||||||
VertexShaderCache::InsertByteCode(uid, value, value_size, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
VertexShaderCache::VertexShaderCache()
|
|
||||||
{
|
|
||||||
char* vProg = new char[2048];
|
|
||||||
sprintf(vProg,"struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float2 vTexCoord : TEXCOORD0;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;\n"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vTexCoord = inTEX0;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n");
|
|
||||||
|
|
||||||
SimpleVertexShader[0] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg));
|
|
||||||
|
|
||||||
sprintf(vProg,"struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float4 vColor0 : COLOR0;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;\n"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vColor0 = inColor0;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n");
|
|
||||||
|
|
||||||
ClearVertexShader = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg));
|
|
||||||
|
|
||||||
sprintf(vProg, "struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float4 vTexCoord : TEXCOORD0;\n"
|
|
||||||
"float4 vTexCoord1 : TEXCOORD1;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vTexCoord = inTEX0.xyyx;\n"
|
|
||||||
"OUT.vTexCoord1 = inTEX2;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n");
|
|
||||||
SimpleVertexShader[1] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg));
|
|
||||||
|
|
||||||
sprintf(vProg, "struct VSOUTPUT\n"
|
|
||||||
"{\n"
|
|
||||||
"float4 vPosition : POSITION;\n"
|
|
||||||
"float4 vTexCoord : TEXCOORD0;\n"
|
|
||||||
"float4 vTexCoord1 : TEXCOORD1;\n"
|
|
||||||
"float4 vTexCoord2 : TEXCOORD2;\n"
|
|
||||||
"float4 vTexCoord3 : TEXCOORD3;\n"
|
|
||||||
"};\n"
|
|
||||||
"VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n"
|
|
||||||
"{\n"
|
|
||||||
"VSOUTPUT OUT;"
|
|
||||||
"OUT.vPosition = inPosition;\n"
|
|
||||||
"OUT.vTexCoord = inTEX0.xyyx;\n"
|
|
||||||
"OUT.vTexCoord1 = inTEX0.xyyx + (float4(-1.0f,-0.5f, 1.0f,-0.5f) * inTEX1.xyyx);\n"
|
|
||||||
"OUT.vTexCoord2 = inTEX0.xyyx + (float4( 1.0f, 0.5f,-1.0f, 0.5f) * inTEX1.xyyx);\n"
|
|
||||||
"OUT.vTexCoord3 = inTEX2;\n"
|
|
||||||
"return OUT;\n"
|
|
||||||
"}\n");
|
|
||||||
SimpleVertexShader[2] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg));
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
delete [] vProg;
|
|
||||||
|
|
||||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
|
||||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
|
|
||||||
|
|
||||||
SETSTAT(stats.numVertexShadersCreated, 0);
|
|
||||||
SETSTAT(stats.numVertexShadersAlive, 0);
|
|
||||||
|
|
||||||
char cache_filename[MAX_PATH];
|
|
||||||
sprintf(cache_filename, "%sdx9-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
|
|
||||||
VertexShaderCacheInserter inserter;
|
|
||||||
int read_items = g_vs_disk_cache.OpenAndRead(cache_filename, &inserter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::Clear()
|
|
||||||
{
|
|
||||||
VSCache::iterator
|
|
||||||
iter = vshaders.begin(),
|
|
||||||
vsend = vshaders.end();
|
|
||||||
for (; iter != vsend; ++iter)
|
|
||||||
iter->second.Destroy();
|
|
||||||
|
|
||||||
vshaders.clear();
|
|
||||||
|
|
||||||
memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid));
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexShaderCache::~VertexShaderCache()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_SSAA_SHADERS; i++)
|
|
||||||
{
|
|
||||||
if (SimpleVertexShader[i])
|
|
||||||
SimpleVertexShader[i]->Release();
|
|
||||||
SimpleVertexShader[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ClearVertexShader)
|
|
||||||
ClearVertexShader->Release();
|
|
||||||
|
|
||||||
ClearVertexShader = NULL;
|
|
||||||
|
|
||||||
g_vs_disk_cache.Sync();
|
|
||||||
g_vs_disk_cache.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VertexShaderCache::SetShader(u32 components)
|
|
||||||
{
|
|
||||||
DVSTARTPROFILE();
|
|
||||||
|
|
||||||
VERTEXSHADERUID uid;
|
|
||||||
GetVertexShaderId(&uid, components);
|
|
||||||
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
|
|
||||||
{
|
|
||||||
if (vshaders[uid].shader)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID));
|
|
||||||
|
|
||||||
VSCache::iterator iter;
|
|
||||||
iter = vshaders.find(uid);
|
|
||||||
if (iter != vshaders.end())
|
|
||||||
{
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
const VSCacheEntry &entry = iter->second;
|
|
||||||
last_entry = &entry;
|
|
||||||
|
|
||||||
//DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
|
||||||
if (entry.shader)
|
|
||||||
{
|
|
||||||
D3D::SetVertexShader(entry.shader);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *code = GenerateVertexShaderCode(components, API_D3D9);
|
|
||||||
u8 *bytecode;
|
|
||||||
int bytecodelen;
|
|
||||||
if (!D3D::CompileVertexShader(code, (int)strlen(code), &bytecode, &bytecodelen))
|
|
||||||
{
|
|
||||||
if (g_ActiveConfig.bShowShaderErrors)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to compile Vertex Shader:\n\n%s", code);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
g_vs_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen);
|
|
||||||
g_vs_disk_cache.Sync();
|
|
||||||
|
|
||||||
bool result = InsertByteCode(uid, bytecode, bytecodelen, true);
|
|
||||||
delete [] bytecode;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) {
|
|
||||||
LPDIRECT3DVERTEXSHADER9 shader = D3D::CreateVertexShaderFromByteCode(bytecode, bytecodelen);
|
|
||||||
|
|
||||||
// Make an entry in the table
|
|
||||||
VSCacheEntry entry;
|
|
||||||
entry.shader = shader;
|
|
||||||
entry.frameCount = frameCount;
|
|
||||||
|
|
||||||
vshaders[uid] = entry;
|
|
||||||
last_entry = &vshaders[uid];
|
|
||||||
if (!shader)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
INCSTAT(stats.numVertexShadersCreated);
|
|
||||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
|
|
||||||
if (activate)
|
|
||||||
{
|
|
||||||
D3D::SetVertexShader(shader);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string VertexShaderCache::GetCurrentShaderCode()
|
|
||||||
{
|
|
||||||
return "(N/A)\n";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,81 +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 "DX9_D3DBase.h"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "DX9_D3DBase.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
#include "../VertexShaderCache.h"
|
|
||||||
|
|
||||||
namespace DX9
|
|
||||||
{
|
|
||||||
|
|
||||||
class VertexShaderCache : public ::VertexShaderCacheBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
struct VSCacheEntry
|
|
||||||
{
|
|
||||||
LPDIRECT3DVERTEXSHADER9 shader;
|
|
||||||
int frameCount;
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string code;
|
|
||||||
#endif
|
|
||||||
VSCacheEntry() : shader(NULL), frameCount(0) {}
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
if (shader)
|
|
||||||
shader->Release();
|
|
||||||
shader = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<VERTEXSHADERUID, VSCacheEntry> VSCache;
|
|
||||||
|
|
||||||
static VSCache vshaders;
|
|
||||||
static const VSCacheEntry *last_entry;
|
|
||||||
static void Clear();
|
|
||||||
|
|
||||||
public:
|
|
||||||
VertexShaderCache();
|
|
||||||
~VertexShaderCache();
|
|
||||||
|
|
||||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetVSConstant4fv(unsigned int const_number, const float *f);
|
|
||||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
|
|
||||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
|
||||||
|
|
||||||
bool SetShader(u32 components);
|
|
||||||
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 GetSimpleVertexShader(int level);
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 GetClearVertexShader();
|
|
||||||
static bool InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate);
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
static std::string GetCurrentShaderCode();
|
|
||||||
#endif
|
|
||||||
static LPDIRECT3DVERTEXSHADER9 CompileCgShader(const char *pstrprogram);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _VERTEXSHADERCACHE_H
|
|
|
@ -1,233 +0,0 @@
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
|
|
||||||
#include "EmuWindow.h"
|
|
||||||
|
|
||||||
int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0;
|
|
||||||
|
|
||||||
namespace EmuWindow
|
|
||||||
{
|
|
||||||
|
|
||||||
HWND m_hWnd = NULL;
|
|
||||||
HWND m_hParent = NULL;
|
|
||||||
HINSTANCE m_hInstance = NULL;
|
|
||||||
WNDCLASSEX wndClass;
|
|
||||||
const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
|
|
||||||
int g_winstyle;
|
|
||||||
static volatile bool s_sizing;
|
|
||||||
|
|
||||||
bool IsSizing()
|
|
||||||
{
|
|
||||||
return s_sizing;
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND GetWnd()
|
|
||||||
{
|
|
||||||
return m_hWnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND GetParentWnd()
|
|
||||||
{
|
|
||||||
return m_hParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// KeyDown events
|
|
||||||
// -------------
|
|
||||||
void OnKeyDown(WPARAM wParam)
|
|
||||||
{
|
|
||||||
switch (LOWORD( wParam ))
|
|
||||||
{
|
|
||||||
case '3': // OSD keys
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
if (g_Config.bOSDHotKey)
|
|
||||||
OSDMenu(wParam);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
|
|
||||||
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
|
|
||||||
{
|
|
||||||
switch( iMsg )
|
|
||||||
{
|
|
||||||
case WM_PAINT:
|
|
||||||
{
|
|
||||||
HDC hdc;
|
|
||||||
PAINTSTRUCT ps;
|
|
||||||
hdc = BeginPaint(hWnd, &ps);
|
|
||||||
EndPaint(hWnd, &ps);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_ENTERSIZEMOVE:
|
|
||||||
s_sizing = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_EXITSIZEMOVE:
|
|
||||||
s_sizing = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Post thes mouse events to the main window, it's nessesary because in difference to the
|
|
||||||
keyboard inputs these events only appear here, not in the parent window or any other WndProc()*/
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
case WM_LBUTTONDBLCLK:
|
|
||||||
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_CLOSE:
|
|
||||||
// When the user closes the window, we post an event to the main window to call Stop()
|
|
||||||
// Which then handles all the necessary steps to Shutdown the core + the plugins
|
|
||||||
if (m_hParent == NULL)
|
|
||||||
PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_USER:
|
|
||||||
if (wParam == WM_USER_KEYDOWN)
|
|
||||||
OnKeyDown(lParam);
|
|
||||||
else if (wParam == WIIMOTE_DISCONNECT)
|
|
||||||
PostMessage(m_hParent, WM_USER, wParam, lParam);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SYSCOMMAND:
|
|
||||||
switch (wParam)
|
|
||||||
{
|
|
||||||
case SC_SCREENSAVE:
|
|
||||||
case SC_MONITORPOWER:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hWnd, iMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SETCURSOR:
|
|
||||||
PostMessage(m_hParent, WM_USER, WM_USER_SETCURSOR, 0);
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return DefWindowProc(hWnd, iMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// OSD Menu
|
|
||||||
// -------------
|
|
||||||
// Let's begin with 3 since 1 and 2 are default Wii keys
|
|
||||||
// -------------
|
|
||||||
void OSDMenu(WPARAM wParam)
|
|
||||||
{
|
|
||||||
switch( LOWORD( wParam ))
|
|
||||||
{
|
|
||||||
//case '3':
|
|
||||||
// OSDChoice = 1;
|
|
||||||
// // Toggle native resolution
|
|
||||||
// OSDInternalW = D3D::GetBackBufferWidth();
|
|
||||||
// OSDInternalH = D3D::GetBackBufferHeight();
|
|
||||||
// break;
|
|
||||||
case '4':
|
|
||||||
OSDChoice = 2;
|
|
||||||
// Toggle aspect ratio
|
|
||||||
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
OSDChoice = 3;
|
|
||||||
PanicAlert("Toggling EFB copy not implemented!\n");
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
OSDChoice = 4;
|
|
||||||
g_Config.bDisableFog = !g_Config.bDisableFog;
|
|
||||||
break;
|
|
||||||
case '7':
|
|
||||||
OSDChoice = 5;
|
|
||||||
g_Config.bDisableLighting = !g_Config.bDisableLighting;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title)
|
|
||||||
{
|
|
||||||
wndClass.cbSize = sizeof( wndClass );
|
|
||||||
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
|
|
||||||
wndClass.lpfnWndProc = WndProc;
|
|
||||||
wndClass.cbClsExtra = 0;
|
|
||||||
wndClass.cbWndExtra = 0;
|
|
||||||
wndClass.hInstance = hInstance;
|
|
||||||
wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
|
|
||||||
wndClass.hCursor = NULL;
|
|
||||||
wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
|
|
||||||
wndClass.lpszMenuName = NULL;
|
|
||||||
wndClass.lpszClassName = m_szClassName;
|
|
||||||
wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
|
|
||||||
|
|
||||||
m_hInstance = hInstance;
|
|
||||||
RegisterClassEx( &wndClass );
|
|
||||||
|
|
||||||
m_hParent = parent;
|
|
||||||
|
|
||||||
m_hWnd = CreateWindow(m_szClassName, title, WS_CHILD,
|
|
||||||
0, 0, width, height, m_hParent, NULL, hInstance, NULL);
|
|
||||||
|
|
||||||
return m_hWnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Show()
|
|
||||||
{
|
|
||||||
ShowWindow(m_hWnd, SW_SHOW);
|
|
||||||
BringWindowToTop(m_hWnd);
|
|
||||||
UpdateWindow(m_hWnd);
|
|
||||||
SetFocus(m_hParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title)
|
|
||||||
{
|
|
||||||
// TODO:
|
|
||||||
// 1. Remove redundant window manipulation,
|
|
||||||
// 2. Make DX11 in fullscreen can be overlapped by other dialogs
|
|
||||||
// 3. Request window sizes which actually make the client area map to a common resolution
|
|
||||||
HWND Ret;
|
|
||||||
int x=0, y=0, width=640, height=480;
|
|
||||||
g_VideoInitialize.pRequestWindowSize(x, y, width, height);
|
|
||||||
|
|
||||||
Ret = OpenWindow(hParent, hInstance, width, height, title);
|
|
||||||
|
|
||||||
if (Ret)
|
|
||||||
{
|
|
||||||
Show();
|
|
||||||
}
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close()
|
|
||||||
{
|
|
||||||
if (m_hParent == NULL)
|
|
||||||
DestroyWindow(m_hWnd);
|
|
||||||
UnregisterClass(m_szClassName, m_hInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetSize(int width, int height)
|
|
||||||
{
|
|
||||||
RECT rc = {0, 0, width, height};
|
|
||||||
DWORD style = GetWindowLong(m_hWnd, GWL_STYLE);
|
|
||||||
AdjustWindowRect(&rc, style, false);
|
|
||||||
|
|
||||||
int w = rc.right - rc.left;
|
|
||||||
int h = rc.bottom - rc.top;
|
|
||||||
|
|
||||||
rc.left = (1280 - w)/2;
|
|
||||||
rc.right = rc.left + w;
|
|
||||||
rc.top = (1024 - h)/2;
|
|
||||||
rc.bottom = rc.top + h;
|
|
||||||
MoveWindow(m_hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
|
|
||||||
#ifndef _EMUWINDOW_H_
|
|
||||||
#define _EMUWINDOW_H_
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
namespace EmuWindow
|
|
||||||
{
|
|
||||||
|
|
||||||
HWND GetWnd();
|
|
||||||
HWND GetParentWnd();
|
|
||||||
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR* title);
|
|
||||||
void Show();
|
|
||||||
void Close();
|
|
||||||
void SetSize(int displayWidth, int displayHeight);
|
|
||||||
bool IsSizing();
|
|
||||||
void OSDMenu(WPARAM wParam);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,216 +0,0 @@
|
||||||
|
|
||||||
#include "FramebufferManager.h"
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Renderer.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode
|
|
||||||
|
|
||||||
const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[];
|
|
||||||
|
|
||||||
FramebufferManagerBase::~FramebufferManagerBase()
|
|
||||||
{
|
|
||||||
VirtualXFBListType::iterator
|
|
||||||
it = m_virtualXFBList.begin(),
|
|
||||||
vlend = m_virtualXFBList.end();
|
|
||||||
for (; it != vlend; ++it)
|
|
||||||
delete it->xfbSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
const XFBSourceBase** FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
||||||
{
|
|
||||||
//if (g_ActiveConfig.bUseRealXFB)
|
|
||||||
// return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
|
||||||
//else
|
|
||||||
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
|
|
||||||
{
|
|
||||||
return !((aLower >= bUpper) || (bLower >= aUpper));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
//if (g_ActiveConfig.bUseRealXFB)
|
|
||||||
// copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
||||||
//else
|
|
||||||
copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManagerBase::replaceVirtualXFB()
|
|
||||||
{
|
|
||||||
VirtualXFBListType::iterator
|
|
||||||
it = m_virtualXFBList.begin(),
|
|
||||||
vlend = m_virtualXFBList.end();
|
|
||||||
|
|
||||||
VirtualXFB *vxfb = &*it;
|
|
||||||
|
|
||||||
const s32 srcLower = vxfb->xfbAddr;
|
|
||||||
const s32 srcUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
|
|
||||||
const s32 lineSize = 2 * vxfb->xfbWidth;
|
|
||||||
|
|
||||||
while (++it != vlend)
|
|
||||||
{
|
|
||||||
vxfb = &*it;
|
|
||||||
|
|
||||||
const s32 dstLower = vxfb->xfbAddr;
|
|
||||||
const s32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
|
|
||||||
|
|
||||||
if (dstLower >= srcLower && dstUpper <= srcUpper)
|
|
||||||
{
|
|
||||||
// invalidate the data
|
|
||||||
vxfb->xfbAddr = 0;
|
|
||||||
vxfb->xfbHeight = 0;
|
|
||||||
vxfb->xfbWidth = 0;
|
|
||||||
}
|
|
||||||
else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
|
|
||||||
{
|
|
||||||
const s32 upperOverlap = (srcUpper - dstLower) / lineSize;
|
|
||||||
const s32 lowerOverlap = (dstUpper - srcLower) / lineSize;
|
|
||||||
|
|
||||||
if (upperOverlap > 0 && lowerOverlap < 0)
|
|
||||||
{
|
|
||||||
vxfb->xfbAddr += lineSize * upperOverlap;
|
|
||||||
vxfb->xfbHeight -= upperOverlap;
|
|
||||||
}
|
|
||||||
else if (lowerOverlap > 0)
|
|
||||||
{
|
|
||||||
vxfb->xfbHeight -= lowerOverlap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferManagerBase::VirtualXFBListType::iterator
|
|
||||||
FramebufferManagerBase::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
|
||||||
{
|
|
||||||
const u32 srcLower = xfbAddr;
|
|
||||||
const u32 srcUpper = xfbAddr + 2 * width * height;
|
|
||||||
|
|
||||||
VirtualXFBListType::iterator
|
|
||||||
it = m_virtualXFBList.begin(),
|
|
||||||
vlend = m_virtualXFBList.end();
|
|
||||||
for (; it != vlend; ++it)
|
|
||||||
{
|
|
||||||
const VirtualXFB &vxfb = *it;
|
|
||||||
|
|
||||||
const u32 dstLower = vxfb.xfbAddr;
|
|
||||||
const u32 dstUpper = vxfb.xfbAddr + 2 * vxfb.xfbWidth * vxfb.xfbHeight;
|
|
||||||
|
|
||||||
if (dstLower >= srcLower && dstUpper <= srcUpper)
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// That address is not in the Virtual XFB list.
|
|
||||||
return m_virtualXFBList.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManagerBase::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
const VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight);
|
|
||||||
|
|
||||||
VirtualXFB *vxfb = NULL;
|
|
||||||
|
|
||||||
if (m_virtualXFBList.end() == it)
|
|
||||||
{
|
|
||||||
if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
|
|
||||||
{
|
|
||||||
PanicAlert("Requested creating a new virtual XFB although the maximum number has already been reached! Report this to the devs");
|
|
||||||
return;
|
|
||||||
// TODO, possible alternative to failing: just delete the oldest virtual XFB:
|
|
||||||
// delete m_virtualXFBList.back().xfbSource;
|
|
||||||
// m_virtualXFBList.pop_back();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// create a new Virtual XFB and place it at the front of the list
|
|
||||||
VirtualXFB v;
|
|
||||||
m_virtualXFBList.push_front(v);
|
|
||||||
vxfb = &m_virtualXFBList.front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vxfb = &*it;
|
|
||||||
delete vxfb->xfbSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
vxfb->xfbAddr = xfbAddr;
|
|
||||||
vxfb->xfbWidth = fbWidth;
|
|
||||||
vxfb->xfbHeight = fbHeight;
|
|
||||||
|
|
||||||
const float scaleX = RendererBase::GetXFBScaleX();
|
|
||||||
const float scaleY = RendererBase::GetXFBScaleY();
|
|
||||||
|
|
||||||
TargetRectangle targetSource;
|
|
||||||
targetSource.top = (int)(sourceRc.top * scaleY);
|
|
||||||
targetSource.bottom = (int)(sourceRc.bottom * scaleY);
|
|
||||||
targetSource.left = (int)(sourceRc.left * scaleX);
|
|
||||||
targetSource.right = (int)(sourceRc.right * scaleX);
|
|
||||||
|
|
||||||
const unsigned int target_width = targetSource.right - targetSource.left;
|
|
||||||
const unsigned int target_height = targetSource.bottom - targetSource.top;
|
|
||||||
|
|
||||||
vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height);
|
|
||||||
if (NULL == vxfb->xfbSource)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create virtual XFB");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// why do both of these have a height/width/addr ?
|
|
||||||
vxfb->xfbSource->srcAddr = xfbAddr;
|
|
||||||
vxfb->xfbSource->srcWidth = fbWidth;
|
|
||||||
vxfb->xfbSource->srcHeight = fbHeight;
|
|
||||||
|
|
||||||
vxfb->xfbSource->texWidth = target_width;
|
|
||||||
vxfb->xfbSource->texHeight = target_height;
|
|
||||||
|
|
||||||
if (m_virtualXFBList.end() != it)
|
|
||||||
{
|
|
||||||
// move this Virtual XFB to the front of the list.
|
|
||||||
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
|
|
||||||
|
|
||||||
// keep stale XFB data from being used
|
|
||||||
replaceVirtualXFB();
|
|
||||||
}
|
|
||||||
|
|
||||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
|
||||||
|
|
||||||
vxfb->xfbSource->CopyEFB(RendererBase::ConvertEFBRectangle(sourceRc));
|
|
||||||
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
}
|
|
||||||
|
|
||||||
const XFBSourceBase** FramebufferManagerBase::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
||||||
{
|
|
||||||
xfbCount = 0;
|
|
||||||
|
|
||||||
if (0 == m_virtualXFBList.size()) // no Virtual XFBs available
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
u32 srcLower = xfbAddr;
|
|
||||||
u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight;
|
|
||||||
|
|
||||||
VirtualXFBListType::reverse_iterator
|
|
||||||
it = m_virtualXFBList.rbegin(),
|
|
||||||
vlend = m_virtualXFBList.rend();
|
|
||||||
for (; it != vlend; ++it)
|
|
||||||
{
|
|
||||||
VirtualXFB* vxfb = &*it;
|
|
||||||
|
|
||||||
u32 dstLower = vxfb->xfbAddr;
|
|
||||||
u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight;
|
|
||||||
|
|
||||||
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
|
|
||||||
{
|
|
||||||
m_overlappingXFBArray[xfbCount] = vxfb->xfbSource;
|
|
||||||
xfbCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &m_overlappingXFBArray[0];
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
|
|
||||||
#ifndef _FRAMEBUFFERMANAGER_H_
|
|
||||||
#define _FRAMEBUFFERMANAGER_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "CommonTypes.h"
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
|
|
||||||
struct XFBSourceBase
|
|
||||||
{
|
|
||||||
u32 srcAddr;
|
|
||||||
u32 srcWidth;
|
|
||||||
u32 srcHeight;
|
|
||||||
|
|
||||||
unsigned int texWidth;
|
|
||||||
unsigned int texHeight;
|
|
||||||
|
|
||||||
virtual void CopyEFB(const TargetRectangle& efbSource) = 0;
|
|
||||||
|
|
||||||
virtual ~XFBSourceBase() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
XFBSourceBase() : srcAddr(0), srcWidth(0), srcHeight(0), texWidth(0), texHeight(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class FramebufferManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MAX_VIRTUAL_XFB = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~FramebufferManagerBase();
|
|
||||||
|
|
||||||
//virtual void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) = 0;
|
|
||||||
//virtual void Shutdown() = 0;
|
|
||||||
|
|
||||||
static void replaceVirtualXFB();
|
|
||||||
|
|
||||||
static void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
static const XFBSourceBase** GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
|
||||||
static const XFBSourceBase** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
|
||||||
|
|
||||||
//protected:
|
|
||||||
struct VirtualXFB
|
|
||||||
{
|
|
||||||
// Address and size in GameCube RAM
|
|
||||||
u32 xfbAddr;
|
|
||||||
u32 xfbWidth;
|
|
||||||
u32 xfbHeight;
|
|
||||||
|
|
||||||
XFBSourceBase *xfbSource;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height) = 0;
|
|
||||||
|
|
||||||
typedef std::list<VirtualXFB> VirtualXFBListType;
|
|
||||||
static VirtualXFBListType m_virtualXFBList; // used in virtual XFB mode
|
|
||||||
|
|
||||||
static VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
|
|
||||||
|
|
||||||
static void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
static const XFBSourceBase* m_overlappingXFBArray[MAX_VIRTUAL_XFB];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,626 +0,0 @@
|
||||||
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
// TODO: temporary, just used in Video_Prepare
|
|
||||||
// comment out to use (try to use :p) OpenGL
|
|
||||||
#define USE_DX11
|
|
||||||
|
|
||||||
#include <wx/wx.h>
|
|
||||||
#include <wx/notebook.h>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Atomic.h"
|
|
||||||
#include "Thread.h"
|
|
||||||
#include "LogManager.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "VertexLoaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "CommandProcessor.h"
|
|
||||||
#include "PixelEngine.h"
|
|
||||||
#include "OnScreenDisplay.h"
|
|
||||||
#include "VideoState.h"
|
|
||||||
#include "XFBConvert.h"
|
|
||||||
#include "DLCache.h"
|
|
||||||
|
|
||||||
// internal crap
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "TextureCache.h"
|
|
||||||
#include "VertexManager.h"
|
|
||||||
#include "VertexShaderCache.h"
|
|
||||||
#include "PixelShaderCache.h"
|
|
||||||
#include "FramebufferManager.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#include "DX11/DX11_TextureCache.h"
|
|
||||||
#include "DX11/DX11_VertexShaderCache.h"
|
|
||||||
#include "DX11/DX11_PixelShaderCache.h"
|
|
||||||
#include "DX11/DX11_Render.h"
|
|
||||||
#include "DX11/DX11_VertexManager.h"
|
|
||||||
|
|
||||||
#include "DX9/DX9_TextureCache.h"
|
|
||||||
#include "DX9/DX9_VertexShaderCache.h"
|
|
||||||
#include "DX9/DX9_PixelShaderCache.h"
|
|
||||||
#include "DX9/DX9_Render.h"
|
|
||||||
#include "DX9/DX9_VertexManager.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "OGL/OGL_TextureCache.h"
|
|
||||||
#include "OGL/OGL_VertexShaderCache.h"
|
|
||||||
#include "OGL/OGL_PixelShaderCache.h"
|
|
||||||
#include "OGL/OGL_Render.h"
|
|
||||||
#include "OGL/OGL_VertexManager.h"
|
|
||||||
|
|
||||||
#include "EmuWindow.h"
|
|
||||||
|
|
||||||
// TODO: ifdef wx this
|
|
||||||
#include "VideoConfigDiag.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
#define PLUGIN_NAME "Dolphin Video Merge [broken]"
|
|
||||||
#if defined(DEBUGFAST)
|
|
||||||
#define PLUGIN_FULL_NAME PLUGIN_NAME" (DebugFast)"
|
|
||||||
#elif defined(_DEBUG)
|
|
||||||
#define PLUGIN_FULL_NAME PLUGIN_NAME" (Debug)"
|
|
||||||
#else
|
|
||||||
#define PLUGIN_FULL_NAME PLUGIN_NAME
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HINSTANCE g_hInstance = NULL;
|
|
||||||
SVideoInitialize g_VideoInitialize;
|
|
||||||
PLUGIN_GLOBALS *g_globals = NULL;
|
|
||||||
|
|
||||||
const char* const g_gfxapi_names[] =
|
|
||||||
{
|
|
||||||
"Software",
|
|
||||||
"OpenGL",
|
|
||||||
"Direct3D 9",
|
|
||||||
"Direct3D 11",
|
|
||||||
};
|
|
||||||
|
|
||||||
#define INI_NAME "gfx_new.ini"
|
|
||||||
|
|
||||||
// TODO: save to ini file
|
|
||||||
// TODO: move to VideoConfig or something
|
|
||||||
int g_gfxapi = 3;
|
|
||||||
|
|
||||||
// shits
|
|
||||||
RendererBase *g_renderer;
|
|
||||||
TextureCacheBase *g_texture_cache;
|
|
||||||
VertexManagerBase *g_vertex_manager;
|
|
||||||
VertexShaderCacheBase* g_vertex_shader_cache;
|
|
||||||
PixelShaderCacheBase* g_pixel_shader_cache;
|
|
||||||
FramebufferManagerBase* g_framebuffer_manager;
|
|
||||||
|
|
||||||
static bool s_PluginInitialized = false;
|
|
||||||
volatile u32 s_swapRequested = false;
|
|
||||||
static u32 s_efbAccessRequested = false;
|
|
||||||
static volatile u32 s_FifoShuttingDown = false;
|
|
||||||
|
|
||||||
int frameCount;
|
|
||||||
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
|
||||||
class wxDLLApp : public wxApp
|
|
||||||
{
|
|
||||||
bool OnInit()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
|
||||||
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|
||||||
{
|
|
||||||
switch (fdwReason)
|
|
||||||
{
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
wxSetInstance(hinstDLL);
|
|
||||||
wxInitialize();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
wxUninitialize();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hInstance = hinstDLL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static volatile struct
|
|
||||||
{
|
|
||||||
u32 xfbAddr;
|
|
||||||
FieldType field;
|
|
||||||
u32 fbWidth;
|
|
||||||
u32 fbHeight;
|
|
||||||
} s_beginFieldArgs;
|
|
||||||
|
|
||||||
static inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
|
|
||||||
{
|
|
||||||
return !((aLower >= bUpper) || (bLower >= aUpper));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run from the graphics thread (from Fifo.cpp)
|
|
||||||
void VideoFifo_CheckSwapRequest()
|
|
||||||
{
|
|
||||||
if(g_ActiveConfig.bUseXFB)
|
|
||||||
{
|
|
||||||
if (Common::AtomicLoadAcquire(s_swapRequested))
|
|
||||||
{
|
|
||||||
EFBRectangle rc;
|
|
||||||
g_renderer->Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field,
|
|
||||||
s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight, rc);
|
|
||||||
Common::AtomicStoreRelease(s_swapRequested, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run from the graphics thread (from Fifo.cpp)
|
|
||||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
|
||||||
{
|
|
||||||
if (g_ActiveConfig.bUseXFB)
|
|
||||||
{
|
|
||||||
if(Common::AtomicLoadAcquire(s_swapRequested))
|
|
||||||
{
|
|
||||||
u32 aLower = xfbAddr;
|
|
||||||
u32 aUpper = xfbAddr + 2 * fbWidth * fbHeight;
|
|
||||||
u32 bLower = s_beginFieldArgs.xfbAddr;
|
|
||||||
u32 bUpper = s_beginFieldArgs.xfbAddr + 2 * s_beginFieldArgs.fbWidth * s_beginFieldArgs.fbHeight;
|
|
||||||
|
|
||||||
if (addrRangesOverlap(aLower, aUpper, bLower, bUpper))
|
|
||||||
VideoFifo_CheckSwapRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct
|
|
||||||
{
|
|
||||||
EFBAccessType type;
|
|
||||||
u32 x;
|
|
||||||
u32 y;
|
|
||||||
u32 Data;
|
|
||||||
} s_accessEFBArgs;
|
|
||||||
|
|
||||||
static u32 s_AccessEFBResult = 0;
|
|
||||||
|
|
||||||
void VideoFifo_CheckEFBAccess()
|
|
||||||
{
|
|
||||||
if (Common::AtomicLoadAcquire(s_efbAccessRequested))
|
|
||||||
{
|
|
||||||
s_AccessEFBResult = g_renderer->AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y);
|
|
||||||
|
|
||||||
Common::AtomicStoreRelease(s_efbAccessRequested, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoFifo_CheckAsyncRequest()
|
|
||||||
{
|
|
||||||
VideoFifo_CheckSwapRequest();
|
|
||||||
VideoFifo_CheckEFBAccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Callback_PeekMessages()
|
|
||||||
{
|
|
||||||
MSG msg;
|
|
||||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
||||||
{
|
|
||||||
if (msg.message == WM_QUIT)
|
|
||||||
return 0;
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateFPSDisplay(const char *text)
|
|
||||||
{
|
|
||||||
char temp[512];
|
|
||||||
sprintf_s(temp, 512, "SVN R%s: DX11: %s", svn_rev_str, text);
|
|
||||||
SetWindowTextA(EmuWindow::GetWnd(), temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GLOBAL I N T E R F A C E
|
|
||||||
// ____________________________________________________________________________
|
|
||||||
// Function: GetDllInfo
|
|
||||||
// Purpose: This function allows the emulator to gather information
|
|
||||||
// about the DLL by filling in the PluginInfo structure.
|
|
||||||
// input: A pointer to a PLUGIN_INFO structure that needs to be
|
|
||||||
// filled by the function. (see def above)
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void GetDllInfo(PLUGIN_INFO* _pPluginInfo)
|
|
||||||
{
|
|
||||||
memcpy(_pPluginInfo->Name, PLUGIN_FULL_NAME, sizeof(PLUGIN_FULL_NAME));
|
|
||||||
_pPluginInfo->Type = PLUGIN_TYPE_VIDEO;
|
|
||||||
_pPluginInfo->Version = 0x0100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: DllConfig
|
|
||||||
// Purpose: This function is optional function that is provided
|
|
||||||
// to allow the user to configure the DLL
|
|
||||||
// input: A handle to the window that calls this function
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void DllConfig(void *_hParent)
|
|
||||||
{
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
|
||||||
|
|
||||||
VideoConfigDiag* const m_config_diag = new VideoConfigDiag((wxWindow *)_hParent);
|
|
||||||
m_config_diag->ShowModal();
|
|
||||||
m_config_diag->Destroy();
|
|
||||||
|
|
||||||
g_Config.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str());
|
|
||||||
|
|
||||||
SLEEP(50); // hax to keep Dolphin window from staying hidden
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: DllDebugger
|
|
||||||
// Purpose: Open the debugger
|
|
||||||
// input: a handle to the window that calls this function
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void* DllDebugger(void *_hParent, bool Show)
|
|
||||||
{
|
|
||||||
// TODO:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: DllSetGlobals
|
|
||||||
// Purpose: Set the pointer for globals variables
|
|
||||||
// input: a pointer to the global struct
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
|
|
||||||
{
|
|
||||||
g_globals = _pPluginGlobals;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: Initialize
|
|
||||||
// Purpose: Initialize the plugin
|
|
||||||
// input: Init
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Initialize(void *init)
|
|
||||||
{
|
|
||||||
frameCount = 0;
|
|
||||||
|
|
||||||
g_VideoInitialize = *(SVideoInitialize*)init;
|
|
||||||
|
|
||||||
InitXFBConvTables();
|
|
||||||
|
|
||||||
g_Config.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str());
|
|
||||||
g_Config.GameIniLoad(g_globals->game_ini);
|
|
||||||
UpdateActiveConfig();
|
|
||||||
|
|
||||||
g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create((HWND)g_VideoInitialize.pWindowHandle, g_hInstance, _T("Loading - Please wait."));
|
|
||||||
if (NULL == g_VideoInitialize.pWindowHandle)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "An error has occurred while trying to create the window.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_VideoInitialize.pPeekMessages = Callback_PeekMessages;
|
|
||||||
g_VideoInitialize.pUpdateFPSDisplay = UpdateFPSDisplay;
|
|
||||||
|
|
||||||
*(SVideoInitialize*)init = g_VideoInitialize;
|
|
||||||
|
|
||||||
//OSD::AddMessage("Dolphin ... Video Plugin", 5000);
|
|
||||||
s_PluginInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: Shutdown
|
|
||||||
// Purpose: This function is called when the emulator is shutting down
|
|
||||||
// a game allowing the dll to de-initialise.
|
|
||||||
// input: none
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Shutdown(void)
|
|
||||||
{
|
|
||||||
s_efbAccessRequested = false;
|
|
||||||
s_FifoShuttingDown = false;
|
|
||||||
s_swapRequested = false;
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
DLCache::Shutdown();
|
|
||||||
CommandProcessor::Shutdown();
|
|
||||||
PixelShaderManager::Shutdown();
|
|
||||||
VertexShaderManager::Shutdown();
|
|
||||||
OpcodeDecoder_Shutdown();
|
|
||||||
VertexLoaderManager::Shutdown();
|
|
||||||
Fifo_Shutdown();
|
|
||||||
|
|
||||||
// internal interfaces
|
|
||||||
EmuWindow::Close();
|
|
||||||
|
|
||||||
s_PluginInitialized = false;
|
|
||||||
|
|
||||||
delete g_pixel_shader_cache;
|
|
||||||
delete g_vertex_shader_cache;
|
|
||||||
delete g_vertex_manager;
|
|
||||||
delete g_texture_cache;
|
|
||||||
delete g_renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: DoState
|
|
||||||
// Purpose: Saves/load state
|
|
||||||
// input/output: ptr
|
|
||||||
// input: mode
|
|
||||||
//
|
|
||||||
void DoState(unsigned char **ptr, int mode)
|
|
||||||
{
|
|
||||||
PanicAlert("DoState");
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________________________________________________________________________
|
|
||||||
// Function: EmuStateChange
|
|
||||||
// Purpose: Notifies the plugin of a change in emulation state
|
|
||||||
// input: newState
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void EmuStateChange(PLUGIN_EMUSTATE newState)
|
|
||||||
{
|
|
||||||
Fifo_RunLoop(newState == PLUGIN_EMUSTATE_PLAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I N T E R F A C E
|
|
||||||
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_Prepare
|
|
||||||
// Purpose: This function is called from the EmuThread before the
|
|
||||||
// emulation has started. It is just for threadsensitive
|
|
||||||
// APIs like OpenGL.
|
|
||||||
// input: none
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_Prepare(void)
|
|
||||||
{
|
|
||||||
s_efbAccessRequested = false;
|
|
||||||
s_FifoShuttingDown = false;
|
|
||||||
s_swapRequested = false;
|
|
||||||
|
|
||||||
switch (g_gfxapi)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
case GFXAPI_D3D9:
|
|
||||||
g_renderer = new DX9::Renderer;
|
|
||||||
g_texture_cache = new DX9::TextureCache;
|
|
||||||
g_vertex_manager = new DX9::VertexManager;
|
|
||||||
g_vertex_shader_cache = new DX9::VertexShaderCache;
|
|
||||||
g_pixel_shader_cache = new DX9::PixelShaderCache;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GFXAPI_D3D11:
|
|
||||||
g_renderer = new DX11::Renderer;
|
|
||||||
g_texture_cache = new DX11::TextureCache;
|
|
||||||
g_vertex_manager = new DX11::VertexManager;
|
|
||||||
g_vertex_shader_cache = new DX11::VertexShaderCache;
|
|
||||||
g_pixel_shader_cache = new DX11::PixelShaderCache;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
|
||||||
case GFXAPI_OPENGL:
|
|
||||||
g_renderer = new OGL::Renderer;
|
|
||||||
g_texture_cache = new OGL::TextureCache;
|
|
||||||
g_vertex_manager = new OGL::VertexManager;
|
|
||||||
g_vertex_shader_cache = new OGL::VertexShaderCache;
|
|
||||||
g_pixel_shader_cache = new OGL::PixelShaderCache;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
BPInit();
|
|
||||||
Fifo_Init();
|
|
||||||
VertexLoaderManager::Init();
|
|
||||||
OpcodeDecoder_Init();
|
|
||||||
VertexShaderManager::Init();
|
|
||||||
PixelShaderManager::Init();
|
|
||||||
CommandProcessor::Init();
|
|
||||||
PixelEngine::Init();
|
|
||||||
DLCache::Init();
|
|
||||||
|
|
||||||
// tell the host that the window is ready
|
|
||||||
g_VideoInitialize.pCoreMessage(WM_USER_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_BeginField
|
|
||||||
// Purpose: When a field begins in the VI emulator, this function tells the video plugin what the
|
|
||||||
// parameters of the upcoming field are. The video plugin should make sure the previous
|
|
||||||
// field is on the player's display before returning.
|
|
||||||
// input: vi parameters of the upcoming field
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
|
||||||
{
|
|
||||||
if (s_PluginInitialized && g_ActiveConfig.bUseXFB)
|
|
||||||
{
|
|
||||||
if (g_VideoInitialize.bOnThread)
|
|
||||||
{
|
|
||||||
while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown)
|
|
||||||
//Common::SleepCurrentThread(1);
|
|
||||||
Common::YieldCPU();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
VideoFifo_CheckSwapRequest();
|
|
||||||
s_beginFieldArgs.xfbAddr = xfbAddr;
|
|
||||||
s_beginFieldArgs.field = field;
|
|
||||||
s_beginFieldArgs.fbWidth = fbWidth;
|
|
||||||
s_beginFieldArgs.fbHeight = fbHeight;
|
|
||||||
|
|
||||||
Common::AtomicStoreRelease(s_swapRequested, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_EndField
|
|
||||||
// Purpose: When a field ends in the VI emulator, this function notifies the video plugin. The video
|
|
||||||
// has permission to swap the field to the player's display.
|
|
||||||
// input: none
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_EndField()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_AccessEFB
|
|
||||||
// input: type of access (r/w, z/color, ...), x coord, y coord
|
|
||||||
// output: response to the access request (ex: peek z data at specified coord)
|
|
||||||
//
|
|
||||||
u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
|
|
||||||
{
|
|
||||||
if (s_PluginInitialized)
|
|
||||||
{
|
|
||||||
s_accessEFBArgs.type = type;
|
|
||||||
s_accessEFBArgs.x = x;
|
|
||||||
s_accessEFBArgs.y = y;
|
|
||||||
s_accessEFBArgs.Data = InputData;
|
|
||||||
Common::AtomicStoreRelease(s_efbAccessRequested, true);
|
|
||||||
|
|
||||||
if (g_VideoInitialize.bOnThread)
|
|
||||||
{
|
|
||||||
while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown)
|
|
||||||
//Common::SleepCurrentThread(1);
|
|
||||||
Common::YieldCPU();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
VideoFifo_CheckEFBAccess();
|
|
||||||
|
|
||||||
return s_AccessEFBResult;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_Screenshot
|
|
||||||
// input: Filename
|
|
||||||
// output: true if all was okay
|
|
||||||
//
|
|
||||||
void Video_Screenshot(const char *_szFilename)
|
|
||||||
{
|
|
||||||
PanicAlert("Screenshots are not yet supported.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_EnterLoop
|
|
||||||
// Purpose: Enters the video fifo dispatch loop. This is only used in Dual Core mode.
|
|
||||||
// input: none
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_EnterLoop()
|
|
||||||
{
|
|
||||||
Fifo_EnterLoop(g_VideoInitialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_ExitLoop
|
|
||||||
// Purpose: Exits the video dispatch loop. This is only used in Dual Core mode.
|
|
||||||
// input: none
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_ExitLoop()
|
|
||||||
{
|
|
||||||
Fifo_ExitLoop();
|
|
||||||
s_FifoShuttingDown = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_SetRendering
|
|
||||||
// Purpose: Sets video rendering on and off. Currently used for frame skipping
|
|
||||||
// input: Enabled toggle
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_SetRendering(bool bEnabled)
|
|
||||||
{
|
|
||||||
PanicAlert("SetRendering is not yet supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_AddMessage
|
|
||||||
// Purpose: Adds a message to the display queue, to be shown forthe specified time
|
|
||||||
// input: pointer to the null-terminated string, time in milliseconds
|
|
||||||
// output: none
|
|
||||||
//
|
|
||||||
void Video_AddMessage(const char* pstr, unsigned int milliseconds)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address)
|
|
||||||
{
|
|
||||||
CommandProcessor::Read16(_rReturnValue, _Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address)
|
|
||||||
{
|
|
||||||
CommandProcessor::Write16(_Data, _Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address)
|
|
||||||
{
|
|
||||||
PixelEngine::Read16(_rReturnValue, _Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address)
|
|
||||||
{
|
|
||||||
PixelEngine::Write16(_Data, _Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address)
|
|
||||||
{
|
|
||||||
PixelEngine::Write32(_Data, _Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_GatherPipeBursted(void)
|
|
||||||
{
|
|
||||||
CommandProcessor::GatherPipeBursted();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_WaitForFrameFinish(void)
|
|
||||||
{
|
|
||||||
CommandProcessor::WaitForFrameFinish();
|
|
||||||
}
|
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
|
||||||
// Function: Video_IsFifoBusy
|
|
||||||
// Purpose: Return if the FIFO is proecessing data, that is used for sync gfx thread and emulator
|
|
||||||
// thread in CoreTiming
|
|
||||||
// input: none
|
|
||||||
// output: bool
|
|
||||||
//
|
|
||||||
bool Video_IsFifoBusy(void)
|
|
||||||
{
|
|
||||||
return CommandProcessor::isFifoBusy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Video_AbortFrame(void)
|
|
||||||
{
|
|
||||||
CommandProcessor::AbortFrame();
|
|
||||||
}
|
|
|
@ -1,57 +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 _MAIN_H_
|
|
||||||
#define _MAIN_H_
|
|
||||||
|
|
||||||
#include "PluginSpecs_Video.h"
|
|
||||||
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "TextureCache.h"
|
|
||||||
#include "VertexManager.h"
|
|
||||||
#include "PixelShaderCache.h"
|
|
||||||
#include "VertexShaderCache.h"
|
|
||||||
#include "FramebufferManager.h"
|
|
||||||
|
|
||||||
extern SVideoInitialize g_VideoInitialize;
|
|
||||||
extern volatile u32 s_swapRequested;
|
|
||||||
extern PLUGIN_GLOBALS *g_globals;
|
|
||||||
|
|
||||||
extern RendererBase *g_renderer;
|
|
||||||
extern TextureCacheBase *g_texture_cache;
|
|
||||||
extern VertexManagerBase *g_vertex_manager;
|
|
||||||
extern VertexShaderCacheBase* g_vertex_shader_cache;
|
|
||||||
extern PixelShaderCacheBase* g_pixel_shader_cache;
|
|
||||||
extern FramebufferManagerBase* g_framebuffer_manager;
|
|
||||||
|
|
||||||
extern int frameCount;
|
|
||||||
|
|
||||||
void VideoFifo_CheckEFBAccess();
|
|
||||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
GFXAPI_SOFTWARE,
|
|
||||||
GFXAPI_OPENGL,
|
|
||||||
GFXAPI_D3D9,
|
|
||||||
GFXAPI_D3D11,
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const char* const g_gfxapi_names[];
|
|
||||||
extern int g_gfxapi;
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,385 +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/
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_XFB.h"
|
|
||||||
#include "OGL_FramebufferManager.h"
|
|
||||||
#include "OGL_TextureConverter.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp
|
|
||||||
|
|
||||||
int FramebufferManager::m_targetWidth;
|
|
||||||
int FramebufferManager::m_targetHeight;
|
|
||||||
int FramebufferManager::m_msaaSamples;
|
|
||||||
int FramebufferManager::m_msaaCoverageSamples;
|
|
||||||
|
|
||||||
GLuint FramebufferManager::m_efbFramebuffer;
|
|
||||||
GLuint FramebufferManager::m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
|
|
||||||
GLuint FramebufferManager::m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
|
|
||||||
|
|
||||||
// Only used in MSAA mode.
|
|
||||||
GLuint FramebufferManager::m_resolvedFramebuffer;
|
|
||||||
GLuint FramebufferManager::m_resolvedColorTexture;
|
|
||||||
GLuint FramebufferManager::m_resolvedDepthTexture;
|
|
||||||
|
|
||||||
GLuint FramebufferManager::m_xfbFramebuffer; // Only used in MSAA mode
|
|
||||||
XFBSource FramebufferManager::m_realXFBSource; // Only used in Real XFB mode
|
|
||||||
|
|
||||||
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
|
|
||||||
{
|
|
||||||
// m_efbFramebuffer(0),
|
|
||||||
// m_efbColor(0),
|
|
||||||
// m_efbDepth(0),
|
|
||||||
// m_resolvedFramebuffer(0),
|
|
||||||
// m_resolvedColorTexture(0),
|
|
||||||
// m_resolvedDepthTexture(0),
|
|
||||||
// m_xfbFramebuffer(0)
|
|
||||||
|
|
||||||
m_targetWidth = targetWidth;
|
|
||||||
m_targetHeight = targetHeight;
|
|
||||||
m_msaaSamples = msaaSamples;
|
|
||||||
m_msaaCoverageSamples = msaaCoverageSamples;
|
|
||||||
|
|
||||||
// The EFB can be set to different pixel formats by the game through the
|
|
||||||
// BPMEM_ZCOMPARE register (which should probably have a different name).
|
|
||||||
// They are:
|
|
||||||
// - 24-bit RGB (8-bit components) with 24-bit Z
|
|
||||||
// - 24-bit RGBA (6-bit components) with 24-bit Z
|
|
||||||
// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
|
|
||||||
// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
|
|
||||||
// Multisampling depends on user settings.
|
|
||||||
// The distinction becomes important for certain operations, i.e. the
|
|
||||||
// alpha channel should be ignored if the EFB does not have one.
|
|
||||||
|
|
||||||
// Create EFB target.
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, &m_efbFramebuffer);
|
|
||||||
|
|
||||||
if (m_msaaSamples <= 1)
|
|
||||||
{
|
|
||||||
// EFB targets will be textures in non-MSAA mode.
|
|
||||||
|
|
||||||
GLuint glObj[2];
|
|
||||||
glGenTextures(2, glObj);
|
|
||||||
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_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_ARB, 0);
|
|
||||||
|
|
||||||
// Bind target textures to the EFB framebuffer.
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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);
|
|
||||||
|
|
||||||
GL_REPORT_FBO_ERROR();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
|
|
||||||
// Resolve targets will be created to transfer EFB to RAM textures.
|
|
||||||
// XFB framebuffer will be created to transfer EFB to XFB texture.
|
|
||||||
|
|
||||||
// Create EFB target renderbuffers.
|
|
||||||
|
|
||||||
GLuint glObj[2];
|
|
||||||
glGenRenderbuffersEXT(2, glObj);
|
|
||||||
m_efbColor = glObj[0];
|
|
||||||
m_efbDepth = glObj[1];
|
|
||||||
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
|
|
||||||
if (m_msaaCoverageSamples)
|
|
||||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
|
||||||
else
|
|
||||||
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
|
||||||
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
|
|
||||||
if (m_msaaCoverageSamples)
|
|
||||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, 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);
|
|
||||||
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
|
||||||
|
|
||||||
// Bind target renderbuffers to EFB framebuffer.
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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);
|
|
||||||
|
|
||||||
GL_REPORT_FBO_ERROR();
|
|
||||||
|
|
||||||
// Create resolved targets for transferring multisampled EFB to texture.
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(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_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_ARB, 0);
|
|
||||||
|
|
||||||
// Bind resolved textures to resolved framebuffer.
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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);
|
|
||||||
|
|
||||||
GL_REPORT_FBO_ERROR();
|
|
||||||
|
|
||||||
// Return to EFB framebuffer.
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create XFB framebuffer; targets will be created elsewhere.
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
|
|
||||||
|
|
||||||
// EFB framebuffer is currently bound.
|
|
||||||
}
|
|
||||||
|
|
||||||
FramebufferManager::~FramebufferManager()
|
|
||||||
{
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
|
|
||||||
GLuint glObj[3];
|
|
||||||
|
|
||||||
// Note: OpenGL deletion functions silently ignore parameters of "0".
|
|
||||||
|
|
||||||
glObj[0] = m_efbFramebuffer;
|
|
||||||
glObj[1] = m_resolvedFramebuffer;
|
|
||||||
glObj[2] = m_xfbFramebuffer;
|
|
||||||
glDeleteFramebuffersEXT(3, glObj);
|
|
||||||
m_efbFramebuffer = 0;
|
|
||||||
m_xfbFramebuffer = 0;
|
|
||||||
|
|
||||||
glObj[0] = m_resolvedColorTexture;
|
|
||||||
glObj[1] = m_resolvedDepthTexture;
|
|
||||||
glObj[2] = m_realXFBSource.texture;
|
|
||||||
glDeleteTextures(3, glObj);
|
|
||||||
m_resolvedColorTexture = 0;
|
|
||||||
m_resolvedDepthTexture = 0;
|
|
||||||
m_realXFBSource.texture = 0;
|
|
||||||
|
|
||||||
glObj[0] = m_efbColor;
|
|
||||||
glObj[1] = m_efbDepth;
|
|
||||||
if (m_msaaSamples <= 1)
|
|
||||||
glDeleteTextures(2, glObj);
|
|
||||||
else
|
|
||||||
glDeleteRenderbuffersEXT(2, glObj);
|
|
||||||
m_efbColor = 0;
|
|
||||||
m_efbDepth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
|
||||||
{
|
|
||||||
XFBSource* const xfbs = new XFBSource;
|
|
||||||
|
|
||||||
glGenTextures(1, &xfbs->texture);
|
|
||||||
|
|
||||||
return xfbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFBSource::CopyEFB(const TargetRectangle& efbSource)
|
|
||||||
{
|
|
||||||
// Copy EFB to XFB texture
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (m_msaaSamples <= 1)
|
|
||||||
#else
|
|
||||||
if (!s_bHaveFramebufferBlit)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// Just copy the EFB directly.
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
|
|
||||||
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, texWidth, texHeight, 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::m_efbFramebuffer);
|
|
||||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, FramebufferManager::m_xfbFramebuffer);
|
|
||||||
|
|
||||||
// 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::m_efbFramebuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
if (m_msaaSamples <= 1)
|
|
||||||
{
|
|
||||||
return m_efbColor;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
|
||||||
// required.
|
|
||||||
|
|
||||||
TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(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(
|
|
||||||
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);
|
|
||||||
|
|
||||||
return m_resolvedColorTexture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
if (m_msaaSamples <= 1)
|
|
||||||
{
|
|
||||||
return m_efbDepth;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
|
||||||
// required.
|
|
||||||
|
|
||||||
TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(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(
|
|
||||||
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);
|
|
||||||
|
|
||||||
return m_resolvedDepthTexture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
u8* pXFB = Memory_GetPtr(xfbAddr);
|
|
||||||
if (!pXFB)
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
XFB_Write(pXFB, sourceRc, fbWidth, fbHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
const XFBSourceBase** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
|
|
||||||
{
|
|
||||||
xfbCount = 1;
|
|
||||||
|
|
||||||
m_realXFBSource.texWidth = MAX_XFB_WIDTH;
|
|
||||||
m_realXFBSource.texHeight = MAX_XFB_HEIGHT;
|
|
||||||
|
|
||||||
m_realXFBSource.srcAddr = xfbAddr;
|
|
||||||
m_realXFBSource.srcWidth = fbWidth;
|
|
||||||
m_realXFBSource.srcHeight = fbHeight;
|
|
||||||
|
|
||||||
// OpenGL texture coordinates originate at the lower left, which is why
|
|
||||||
// sourceRc.top = fbHeight and sourceRc.bottom = 0.
|
|
||||||
m_realXFBSource.sourceRc.left = 0;
|
|
||||||
m_realXFBSource.sourceRc.top = fbHeight;
|
|
||||||
m_realXFBSource.sourceRc.right = fbWidth;
|
|
||||||
m_realXFBSource.sourceRc.bottom = 0;
|
|
||||||
|
|
||||||
if (!m_realXFBSource.texture)
|
|
||||||
{
|
|
||||||
glGenTextures(1, &m_realXFBSource.texture);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode YUYV data from GameCube RAM
|
|
||||||
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture);
|
|
||||||
|
|
||||||
m_overlappingXFBArray[0] = &m_realXFBSource;
|
|
||||||
|
|
||||||
return &m_overlappingXFBArray[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void FramebufferManager::SetFramebuffer(GLuint fb)
|
|
||||||
{
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : GetEFBFramebuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply AA if enabled
|
|
||||||
GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
return GetEFBColorTexture(source_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
return GetEFBDepthTexture(source_rect);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,135 +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 _OGL_FRAMEBUFFERMANAGER_H_
|
|
||||||
#define _OGL_FRAMEBUFFERMANAGER_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
#include "../FramebufferManager.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// On the GameCube, the game sends a request for the graphics processor to
|
|
||||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
|
||||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
|
||||||
// decided at the time of the copy, and the format is always YUYV. The video
|
|
||||||
// interface is given a pointer to the XFB, which will be decoded and
|
|
||||||
// displayed on the TV.
|
|
||||||
//
|
|
||||||
// There are two ways for Dolphin to emulate this:
|
|
||||||
//
|
|
||||||
// Real XFB mode:
|
|
||||||
//
|
|
||||||
// Dolphin will behave like the GameCube and encode the EFB to
|
|
||||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
|
||||||
// for output to the screen.
|
|
||||||
//
|
|
||||||
// Advantages: Behaves exactly like the GameCube.
|
|
||||||
// Disadvantages: Resolution will be limited.
|
|
||||||
//
|
|
||||||
// Virtual XFB mode:
|
|
||||||
//
|
|
||||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
|
||||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
|
||||||
// The video interface will look up the XFB in the list and use the enhanced
|
|
||||||
// data stored there, if available.
|
|
||||||
//
|
|
||||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
|
||||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
|
||||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
|
||||||
|
|
||||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
|
||||||
// virtualize.
|
|
||||||
|
|
||||||
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
|
|
||||||
{
|
|
||||||
return !((aLower >= bUpper) || (bLower >= aUpper));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct XFBSource : XFBSourceBase
|
|
||||||
{
|
|
||||||
XFBSource() : texture(0) {}
|
|
||||||
|
|
||||||
void CopyEFB(const TargetRectangle& efbSource);
|
|
||||||
|
|
||||||
GLuint texture;
|
|
||||||
TargetRectangle sourceRc;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FramebufferManager : public ::FramebufferManagerBase
|
|
||||||
{
|
|
||||||
friend struct XFBSource;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
|
|
||||||
~FramebufferManager();
|
|
||||||
|
|
||||||
// To get the EFB in texture form, these functions may have to transfer
|
|
||||||
// the EFB to a resolved texture first.
|
|
||||||
static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc);
|
|
||||||
static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
static GLuint GetEFBFramebuffer() { return m_efbFramebuffer; }
|
|
||||||
|
|
||||||
// Resolved framebuffer is only used in MSAA mode.
|
|
||||||
static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer; }
|
|
||||||
|
|
||||||
static void SetFramebuffer(GLuint fb);
|
|
||||||
|
|
||||||
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID.
|
|
||||||
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
|
||||||
// If not in MSAA mode, will just return the render target texture ID.
|
|
||||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
|
||||||
static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect);
|
|
||||||
|
|
||||||
// Same as above but for the depth Target.
|
|
||||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
|
||||||
static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect);
|
|
||||||
|
|
||||||
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static GLuint m_efbFramebuffer;
|
|
||||||
static GLuint m_xfbFramebuffer; // Only used in MSAA mode
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
static const XFBSourceBase** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
|
|
||||||
|
|
||||||
static int m_targetWidth;
|
|
||||||
static int m_targetHeight;
|
|
||||||
static int m_msaaSamples;
|
|
||||||
static int m_msaaCoverageSamples;
|
|
||||||
|
|
||||||
static GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
|
|
||||||
static GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
|
|
||||||
|
|
||||||
// Only used in MSAA mode.
|
|
||||||
static GLuint m_resolvedFramebuffer;
|
|
||||||
static GLuint m_resolvedColorTexture;
|
|
||||||
static GLuint m_resolvedDepthTexture;
|
|
||||||
|
|
||||||
static XFBSource m_realXFBSource; // Only used in Real XFB mode
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,514 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "IniFile.h"
|
|
||||||
#include "Setup.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "../EmuWindow.h"
|
|
||||||
extern HINSTANCE g_hInstance;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static HDC hDC = NULL; // Private GDI Device Context
|
|
||||||
static HGLRC hRC = NULL; // Permanent Rendering Context
|
|
||||||
#else
|
|
||||||
GLWindow GLWin;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Handles OpenGL and the window
|
|
||||||
|
|
||||||
// Window dimensions.
|
|
||||||
static int s_backbuffer_width;
|
|
||||||
static int s_backbuffer_height;
|
|
||||||
|
|
||||||
void OpenGL_SwapBuffers()
|
|
||||||
{
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
GLWin.glCanvas->SwapBuffers();
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
cocoaGLSwap(GLWin.cocoaCtx,GLWin.cocoaWin);
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
SwapBuffers(hDC);
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
glXSwapBuffers(GLWin.dpy, GLWin.win);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 OpenGL_GetBackbufferWidth()
|
|
||||||
{
|
|
||||||
return s_backbuffer_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 OpenGL_GetBackbufferHeight()
|
|
||||||
{
|
|
||||||
return s_backbuffer_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGL_SetWindowText(const char *text)
|
|
||||||
{
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
// GLWin.frame->SetTitle(wxString::FromAscii(text));
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
cocoaGLSetTitle(GLWin.cocoaWin, text);
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
// TODO convert text to unicode and change SetWindowTextA to SetWindowText
|
|
||||||
SetWindowTextA(EmuWindow::GetWnd(), text);
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
// Tell X to ask the window manager to set the window title.
|
|
||||||
// (X itself doesn't provide window title functionality.)
|
|
||||||
XStoreName(GLWin.dpy, GLWin.win, text);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(HAVE_X11) && HAVE_X11
|
|
||||||
THREAD_RETURN XEventThread(void *pArg);
|
|
||||||
|
|
||||||
void CreateXWindow (void)
|
|
||||||
{
|
|
||||||
Atom wmProtocols[1];
|
|
||||||
|
|
||||||
// Setup window attributes
|
|
||||||
GLWin.attr.colormap = XCreateColormap(GLWin.dpy,
|
|
||||||
GLWin.parent, GLWin.vi->visual, AllocNone);
|
|
||||||
GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask;
|
|
||||||
GLWin.attr.background_pixel = BlackPixel(GLWin.dpy, GLWin.screen);
|
|
||||||
GLWin.attr.border_pixel = 0;
|
|
||||||
|
|
||||||
// Create the window
|
|
||||||
GLWin.win = XCreateWindow(GLWin.dpy, GLWin.parent,
|
|
||||||
GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual,
|
|
||||||
CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr);
|
|
||||||
wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
|
|
||||||
XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 1);
|
|
||||||
XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL);
|
|
||||||
XMapRaised(GLWin.dpy, GLWin.win);
|
|
||||||
XSync(GLWin.dpy, True);
|
|
||||||
|
|
||||||
GLWin.xEventThread = new Common::Thread(XEventThread, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroyXWindow(void)
|
|
||||||
{
|
|
||||||
XUnmapWindow(GLWin.dpy, GLWin.win);
|
|
||||||
GLWin.win = 0;
|
|
||||||
XFreeColormap(GLWin.dpy, GLWin.attr.colormap);
|
|
||||||
if (GLWin.xEventThread)
|
|
||||||
GLWin.xEventThread->WaitForDeath();
|
|
||||||
GLWin.xEventThread = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
THREAD_RETURN XEventThread(void *pArg)
|
|
||||||
{
|
|
||||||
while (GLWin.win)
|
|
||||||
{
|
|
||||||
XEvent event;
|
|
||||||
KeySym key;
|
|
||||||
for (int num_events = XPending(GLWin.dpy); num_events > 0; num_events--) {
|
|
||||||
XNextEvent(GLWin.dpy, &event);
|
|
||||||
switch(event.type) {
|
|
||||||
case KeyPress:
|
|
||||||
key = XLookupKeysym((XKeyEvent*)&event, 0);
|
|
||||||
switch (key)
|
|
||||||
{
|
|
||||||
case XK_3:
|
|
||||||
OSDChoice = 1;
|
|
||||||
// Toggle native resolution
|
|
||||||
if (!(g_Config.bNativeResolution || g_Config.b2xResolution))
|
|
||||||
g_Config.bNativeResolution = true;
|
|
||||||
else if (g_Config.bNativeResolution && Renderer::AllowCustom())
|
|
||||||
{
|
|
||||||
g_Config.bNativeResolution = false;
|
|
||||||
if (Renderer::Allow2x())
|
|
||||||
g_Config.b2xResolution = true;
|
|
||||||
}
|
|
||||||
else if (Renderer::AllowCustom())
|
|
||||||
g_Config.b2xResolution = false;
|
|
||||||
break;
|
|
||||||
case XK_4:
|
|
||||||
OSDChoice = 2;
|
|
||||||
// Toggle aspect ratio
|
|
||||||
g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3;
|
|
||||||
break;
|
|
||||||
case XK_5:
|
|
||||||
OSDChoice = 3;
|
|
||||||
// Toggle EFB copy
|
|
||||||
if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture)
|
|
||||||
{
|
|
||||||
g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable;
|
|
||||||
g_Config.bCopyEFBToTexture = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XK_6:
|
|
||||||
OSDChoice = 4;
|
|
||||||
g_Config.bDisableFog = !g_Config.bDisableFog;
|
|
||||||
break;
|
|
||||||
case XK_7:
|
|
||||||
OSDChoice = 5;
|
|
||||||
g_Config.bDisableLighting = !g_Config.bDisableLighting;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ConfigureNotify:
|
|
||||||
Window winDummy;
|
|
||||||
unsigned int borderDummy, depthDummy;
|
|
||||||
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
|
|
||||||
&GLWin.width, &GLWin.height, &borderDummy, &depthDummy);
|
|
||||||
s_backbuffer_width = GLWin.width;
|
|
||||||
s_backbuffer_height = GLWin.height;
|
|
||||||
break;
|
|
||||||
case ClientMessage:
|
|
||||||
if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False))
|
|
||||||
g_VideoInitialize.pCoreMessage(WM_USER_STOP);
|
|
||||||
if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESIZE", False))
|
|
||||||
XMoveResizeWindow(GLWin.dpy, GLWin.win, event.xclient.data.l[1],
|
|
||||||
event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Common::SleepCurrentThread(20);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Create rendering window.
|
|
||||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
|
||||||
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight)
|
|
||||||
{
|
|
||||||
int _tx, _ty, _twidth, _theight;
|
|
||||||
g_VideoInitialize.pRequestWindowSize(_tx, _ty, _twidth, _theight);
|
|
||||||
|
|
||||||
// Control window size and picture scaling
|
|
||||||
s_backbuffer_width = _twidth;
|
|
||||||
s_backbuffer_height = _theight;
|
|
||||||
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
|
|
||||||
|
|
||||||
wxSize size(_twidth, _theight);
|
|
||||||
|
|
||||||
GLWin.panel = (wxPanel *)g_VideoInitialize.pWindowHandle;
|
|
||||||
|
|
||||||
GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, args,
|
|
||||||
wxPoint(0,0), size, wxSUNKEN_BORDER);
|
|
||||||
GLWin.glCtxt = new wxGLContext(GLWin.glCanvas);
|
|
||||||
GLWin.glCanvas->Show(TRUE);
|
|
||||||
|
|
||||||
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
GLWin.width = s_backbuffer_width;
|
|
||||||
GLWin.height = s_backbuffer_height;
|
|
||||||
GLWin.cocoaWin = cocoaGLCreateWindow(GLWin.width, GLWin.height);
|
|
||||||
GLWin.cocoaCtx = cocoaGLInit(g_Config.iMultisampleMode);
|
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
|
|
||||||
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
|
|
||||||
{
|
|
||||||
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
|
|
||||||
1, // Version Number
|
|
||||||
PFD_DRAW_TO_WINDOW | // Format Must Support Window
|
|
||||||
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
|
|
||||||
PFD_DOUBLEBUFFER, // Must Support Double Buffering
|
|
||||||
PFD_TYPE_RGBA, // Request An RGBA Format
|
|
||||||
32, // Select Our Color Depth
|
|
||||||
0, 0, 0, 0, 0, 0, // Color Bits Ignored
|
|
||||||
0, // 8bit Alpha Buffer
|
|
||||||
0, // Shift Bit Ignored
|
|
||||||
0, // No Accumulation Buffer
|
|
||||||
0, 0, 0, 0, // Accumulation Bits Ignored
|
|
||||||
24, // 24Bit Z-Buffer (Depth Buffer)
|
|
||||||
8, // 8bit Stencil Buffer
|
|
||||||
0, // No Auxiliary Buffer
|
|
||||||
PFD_MAIN_PLANE, // Main Drawing Layer
|
|
||||||
0, // Reserved
|
|
||||||
0, 0, 0 // Layer Masks Ignored
|
|
||||||
};
|
|
||||||
|
|
||||||
GLuint PixelFormat; // Holds The Results After Searching For A Match
|
|
||||||
|
|
||||||
if (!(hDC=GetDC(EmuWindow::GetWnd()))) {
|
|
||||||
PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) {
|
|
||||||
PanicAlert("(2) Can't find a suitable PixelFormat.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {
|
|
||||||
PanicAlert("(3) Can't set the PixelFormat.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(hRC = wglCreateContext(hDC))) {
|
|
||||||
PanicAlert("(4) Can't create an OpenGL rendering context.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// --------------------------------------
|
|
||||||
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
int glxMajorVersion, glxMinorVersion;
|
|
||||||
|
|
||||||
// attributes for a single buffered visual in RGBA format with at least
|
|
||||||
// 8 bits per color and a 24 bit depth buffer
|
|
||||||
int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
None};
|
|
||||||
|
|
||||||
// attributes for a double buffered visual in RGBA format with at least
|
|
||||||
// 8 bits per color and a 24 bit depth buffer
|
|
||||||
int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
|
|
||||||
GLX_RED_SIZE, 8,
|
|
||||||
GLX_GREEN_SIZE, 8,
|
|
||||||
GLX_BLUE_SIZE, 8,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
|
||||||
GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0,
|
|
||||||
None };
|
|
||||||
|
|
||||||
int attrListDefault[] = {
|
|
||||||
GLX_RGBA,
|
|
||||||
GLX_RED_SIZE, 1,
|
|
||||||
GLX_GREEN_SIZE, 1,
|
|
||||||
GLX_BLUE_SIZE, 1,
|
|
||||||
GLX_DOUBLEBUFFER,
|
|
||||||
GLX_DEPTH_SIZE, 1,
|
|
||||||
None };
|
|
||||||
|
|
||||||
GLWin.dpy = XOpenDisplay(0);
|
|
||||||
GLWin.parent = (Window)g_VideoInitialize.pWindowHandle;
|
|
||||||
GLWin.screen = DefaultScreen(GLWin.dpy);
|
|
||||||
if (GLWin.parent == 0)
|
|
||||||
GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen);
|
|
||||||
|
|
||||||
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
|
|
||||||
NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
|
|
||||||
|
|
||||||
// Get an appropriate visual
|
|
||||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
|
|
||||||
if (GLWin.vi == NULL)
|
|
||||||
{
|
|
||||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
|
|
||||||
if (GLWin.vi != NULL)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Only Singlebuffered Visual!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault);
|
|
||||||
if (GLWin.vi == NULL)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
NOTICE_LOG(VIDEO, "Got Doublebuffered Visual!");
|
|
||||||
|
|
||||||
// Create a GLX context.
|
|
||||||
GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE);
|
|
||||||
if (!GLWin.ctx)
|
|
||||||
{
|
|
||||||
PanicAlert("Couldn't Create GLX context.Quit");
|
|
||||||
exit(0); // TODO: Don't bring down entire Emu
|
|
||||||
}
|
|
||||||
|
|
||||||
GLWin.x = _tx;
|
|
||||||
GLWin.y = _ty;
|
|
||||||
GLWin.width = _twidth;
|
|
||||||
GLWin.height = _theight;
|
|
||||||
|
|
||||||
CreateXWindow();
|
|
||||||
g_VideoInitialize.pWindowHandle = (void *)GLWin.win;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGL_MakeCurrent()
|
|
||||||
{
|
|
||||||
// connect the glx-context to the window
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
cocoaGLMakeCurrent(GLWin.cocoaCtx,GLWin.cocoaWin);
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
return wglMakeCurrent(hDC,hRC) ? true : false;
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
#if defined(HAVE_WX) && (HAVE_WX)
|
|
||||||
g_VideoInitialize.pRequestWindowSize(GLWin.x, GLWin.y, (int&)GLWin.width, (int&)GLWin.height);
|
|
||||||
XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height);
|
|
||||||
#endif
|
|
||||||
return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update window width, size and etc. Called from Render.cpp
|
|
||||||
void OpenGL_Update()
|
|
||||||
{
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
GLWin.glCanvas->GetSize((int *)&GLWin.width, (int *)&GLWin.height);
|
|
||||||
s_backbuffer_width = GLWin.width;
|
|
||||||
s_backbuffer_height = GLWin.height;
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
|
|
||||||
// Is anything needed here?
|
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
RECT rcWindow;
|
|
||||||
if (!EmuWindow::GetParentWnd())
|
|
||||||
{
|
|
||||||
// We are not rendering to a child window - use client size.
|
|
||||||
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We are rendering to a child window - use parent size.
|
|
||||||
GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the new window width and height
|
|
||||||
// See below for documentation
|
|
||||||
int width = rcWindow.right - rcWindow.left;
|
|
||||||
int height = rcWindow.bottom - rcWindow.top;
|
|
||||||
|
|
||||||
// If we are rendering to a child window
|
|
||||||
if (EmuWindow::GetParentWnd() != 0 && (s_backbuffer_width != width || s_backbuffer_height != height) && width >= 4 && height >= 4)
|
|
||||||
{
|
|
||||||
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
|
|
||||||
s_backbuffer_width = width;
|
|
||||||
s_backbuffer_height = height;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Close plugin
|
|
||||||
void OpenGL_Shutdown()
|
|
||||||
{
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
delete GLWin.glCanvas;
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
cocoaGLDeleteWindow(GLWin.cocoaWin);
|
|
||||||
cocoaGLDelete(GLWin.cocoaCtx);
|
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
if (hRC) // Do We Have A Rendering Context?
|
|
||||||
{
|
|
||||||
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
|
|
||||||
{
|
|
||||||
// [F|RES]: if this fails i dont see the message box and
|
|
||||||
// cant get out of the modal state so i disable it.
|
|
||||||
// This function fails only if i render to main window
|
|
||||||
// MessageBox(NULL,"Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Release Rendering Context Failed.");
|
|
||||||
}
|
|
||||||
hRC = NULL; // Set RC To NULL
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "Release Device Context Failed.");
|
|
||||||
hDC = NULL; // Set DC To NULL
|
|
||||||
}
|
|
||||||
EmuWindow::Close();
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
DestroyXWindow();
|
|
||||||
if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL))
|
|
||||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
|
||||||
if (GLWin.ctx)
|
|
||||||
{
|
|
||||||
glXDestroyContext(GLWin.dpy, GLWin.ctx);
|
|
||||||
XCloseDisplay(GLWin.dpy);
|
|
||||||
GLWin.ctx = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line)
|
|
||||||
{
|
|
||||||
GLint err = glGetError();
|
|
||||||
if (err != GL_NO_ERROR)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n", file, line, function, err, gluErrorString(err));
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGL_ReportARBProgramError()
|
|
||||||
{
|
|
||||||
const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
|
||||||
if (pstr != NULL && pstr[0] != 0)
|
|
||||||
{
|
|
||||||
GLint loc = 0;
|
|
||||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
|
|
||||||
ERROR_LOG(VIDEO, "program error at %d: ", loc);
|
|
||||||
ERROR_LOG(VIDEO, (char*)pstr);
|
|
||||||
ERROR_LOG(VIDEO, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
|
||||||
{
|
|
||||||
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
|
||||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
||||||
{
|
|
||||||
const char *error = "-";
|
|
||||||
switch (fbo_status)
|
|
||||||
{
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error = "INCOMPLETE_ATTACHMENT_EXT"; break;
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error = "INCOMPLETE_MISSING_ATTACHMENT_EXT"; break;
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error = "INCOMPLETE_DIMENSIONS_EXT"; break;
|
|
||||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error = "INCOMPLETE_FORMATS_EXT"; 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"; break;
|
|
||||||
}
|
|
||||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n", file, line, function, error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,145 +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 _GLINIT_H_
|
|
||||||
#define _GLINIT_H_
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "MathUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#define GLEW_STATIC
|
|
||||||
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#include <GL/wglew.h>
|
|
||||||
|
|
||||||
#else // linux and apple basic definitions
|
|
||||||
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#include "wx/wx.h"
|
|
||||||
#include "wx/glcanvas.h"
|
|
||||||
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
#include <GL/glxew.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include "Thread.h"
|
|
||||||
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#include "cocoaGL.h"
|
|
||||||
#endif // end USE_WX
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // linux basic definitions
|
|
||||||
|
|
||||||
#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils
|
|
||||||
#define GL_DEPTH_STENCIL_EXT 0x84F9
|
|
||||||
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
|
|
||||||
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
|
|
||||||
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if defined(USE_WX) && USE_WX
|
|
||||||
wxGLCanvas *glCanvas;
|
|
||||||
wxPanel *panel;
|
|
||||||
wxGLContext *glCtxt;
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
NSWindow *cocoaWin;
|
|
||||||
NSOpenGLContext *cocoaCtx;
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
int screen;
|
|
||||||
Window win;
|
|
||||||
Window parent;
|
|
||||||
Display *dpy;
|
|
||||||
XVisualInfo *vi;
|
|
||||||
GLXContext ctx;
|
|
||||||
XSetWindowAttributes attr;
|
|
||||||
Common::Thread *xEventThread;
|
|
||||||
int x, y;
|
|
||||||
#endif
|
|
||||||
unsigned int width, height;
|
|
||||||
} GLWindow;
|
|
||||||
|
|
||||||
extern GLWindow GLWin;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Public OpenGL util
|
|
||||||
|
|
||||||
//#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;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// Initialization / upkeep
|
|
||||||
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height);
|
|
||||||
void OpenGL_Shutdown();
|
|
||||||
void OpenGL_Update();
|
|
||||||
bool OpenGL_MakeCurrent();
|
|
||||||
void OpenGL_SwapBuffers();
|
|
||||||
|
|
||||||
// Get status
|
|
||||||
u32 OpenGL_GetBackbufferWidth();
|
|
||||||
u32 OpenGL_GetBackbufferHeight();
|
|
||||||
|
|
||||||
// Set things
|
|
||||||
void OpenGL_SetWindowText(const char *text);
|
|
||||||
|
|
||||||
// Error reporting - use the convenient macros.
|
|
||||||
void OpenGL_ReportARBProgramError();
|
|
||||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line);
|
|
||||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
#define GL_REPORT_ERROR() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__)
|
|
||||||
#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __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
|
|
||||||
#define GL_REPORT_ERRORD() (void)GL_NO_ERROR
|
|
||||||
#define GL_REPORT_FBO_ERROR() (void)true
|
|
||||||
#define GL_REPORT_PROGRAM_ERROR() (void)0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _GLINIT_H_
|
|
|
@ -1,178 +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 _OGL_GLWINDOW_H_
|
|
||||||
#define _OGL_GLWINDOW_H_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
#include "OGL_Globals.h"
|
|
||||||
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define GLEW_STATIC
|
|
||||||
|
|
||||||
#include <GLew/glew.h>
|
|
||||||
#include <GLew/wglew.h>
|
|
||||||
#include <GLew/gl.h>
|
|
||||||
#include <GLew/glext.h>
|
|
||||||
#else
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
enum OGL_Props
|
|
||||||
{
|
|
||||||
OGL_FULLSCREEN,
|
|
||||||
OGL_KEEPRATIO,
|
|
||||||
OGL_HIDECURSOR,
|
|
||||||
OGL_PROP_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct res
|
|
||||||
{
|
|
||||||
u32 x;
|
|
||||||
u32 y;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GLWindow
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
// TODO: what is xmax and ymax? do we need [xy]render?
|
|
||||||
u32 xWin, yWin; // Windows' size
|
|
||||||
int xOffset, yOffset; // Offset in window
|
|
||||||
float xMax, yMax; // ???
|
|
||||||
u32 xRender, yRender; // Render area
|
|
||||||
|
|
||||||
bool properties[OGL_PROP_COUNT];
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
EventHandler* eventHandler;
|
|
||||||
res origRes, currFullRes, currWinRes;
|
|
||||||
static std::vector<res> fullResolutions;
|
|
||||||
virtual void SetRender(u32 x, u32 y)
|
|
||||||
{
|
|
||||||
xRender = x;
|
|
||||||
yRender = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<res>& getFsResolutions()
|
|
||||||
{
|
|
||||||
return fullResolutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addFSResolution(res fsr)
|
|
||||||
{
|
|
||||||
fullResolutions.push_back(fsr);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual void SwapBuffers() {};
|
|
||||||
virtual void SetWindowText(const char *text) {};
|
|
||||||
virtual bool PeekMessages() {return false;};
|
|
||||||
virtual void Update() {};
|
|
||||||
virtual bool MakeCurrent() {return false;};
|
|
||||||
|
|
||||||
virtual void updateDim()
|
|
||||||
{
|
|
||||||
if (GetProperty(OGL_FULLSCREEN))
|
|
||||||
SetWinSize(currFullRes.x, currFullRes.y);
|
|
||||||
else
|
|
||||||
// Set the windowed resolution
|
|
||||||
SetWinSize(currWinRes.x, currWinRes.y);
|
|
||||||
|
|
||||||
float FactorX = 640.0f / (float)GetXwin();
|
|
||||||
float FactorY = 480.0f / (float)GetYwin();
|
|
||||||
//float Max = (FactorX < FactorY) ? FactorX : FactorY;
|
|
||||||
|
|
||||||
SetMax(1.0f / FactorX, 1.0f / FactorY);
|
|
||||||
SetOffset(0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetEventHandler(EventHandler *eh) { eventHandler = eh;}
|
|
||||||
bool GetProperty(OGL_Props prop) {return properties[prop];}
|
|
||||||
virtual bool SetProperty(OGL_Props prop, bool value)
|
|
||||||
{return properties[prop] = value;}
|
|
||||||
|
|
||||||
u32 GetXrender() {return xRender;}
|
|
||||||
u32 GetYrender() {return yRender;}
|
|
||||||
|
|
||||||
u32 GetXwin() {return xWin;}
|
|
||||||
u32 GetYwin() {return yWin;}
|
|
||||||
void SetWinSize(u32 x, u32 y)
|
|
||||||
{
|
|
||||||
xWin = x;
|
|
||||||
yWin = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetYoff() {return yOffset;}
|
|
||||||
int GetXoff() {return xOffset;}
|
|
||||||
void SetOffset(int x, int y)
|
|
||||||
{
|
|
||||||
yOffset = y;
|
|
||||||
xOffset = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMax(float x, float y)
|
|
||||||
{
|
|
||||||
yMax = y;
|
|
||||||
xMax = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetXmax() {return xMax;}
|
|
||||||
float GetYmax() {return yMax;}
|
|
||||||
|
|
||||||
static bool valid() { return false;}
|
|
||||||
|
|
||||||
GLWindow()
|
|
||||||
{
|
|
||||||
// Load defaults
|
|
||||||
sscanf(g_Config.iFSResolution, "%dx%d",
|
|
||||||
&currFullRes.x, &currFullRes.y);
|
|
||||||
|
|
||||||
sscanf(g_Config.iInternalRes, "%dx%d",
|
|
||||||
&currWinRes.x, &currWinRes.y);
|
|
||||||
|
|
||||||
SetProperty(OGL_FULLSCREEN, g_Config.bFullscreen);
|
|
||||||
// What does this do?
|
|
||||||
SetProperty(OGL_KEEPRATIO, g_Config.bKeepAR43);
|
|
||||||
SetProperty(OGL_HIDECURSOR, g_Config.bHideCursor);
|
|
||||||
|
|
||||||
updateDim();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// setResolution
|
|
||||||
// resolution iter
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _GLWINDOW_H_
|
|
|
@ -1,310 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "x64Emitter.h"
|
|
||||||
#include "ABI.h"
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
#include "NativeVertexWriter.h"
|
|
||||||
#include "CPMemory.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_VertexManager.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
#define COMPILED_CODE_SIZE 4096
|
|
||||||
|
|
||||||
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() const;
|
|
||||||
virtual void EnableComponents(u32 components);
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
inline GLuint VarToGL(VarType t)
|
|
||||||
{
|
|
||||||
static const GLuint lookup[5] = {
|
|
||||||
GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT
|
|
||||||
};
|
|
||||||
return lookup[t];
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
|
||||||
{
|
|
||||||
vertex_stride = _vtx_decl.stride;
|
|
||||||
using namespace Gen;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0);
|
|
||||||
|
|
||||||
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() const {
|
|
||||||
// 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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLVertexFormat::EnableComponents(u32 components)
|
|
||||||
{
|
|
||||||
if (s_prevcomponents != components)
|
|
||||||
{
|
|
||||||
g_vertex_manager->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 (!g_ActiveConfig.bDisableTexturing)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glClientActiveTexture(GL_TEXTURE0 + i);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable Lighting
|
|
||||||
// TODO - Is this a good spot for this code?
|
|
||||||
if (g_ActiveConfig.bDisableLighting)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < xfregs.nNumChans; i++)
|
|
||||||
{
|
|
||||||
xfregs.colChans[i].alpha.enablelighting = false;
|
|
||||||
xfregs.colChans[i].color.enablelighting = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_prevcomponents = components;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,340 +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 <cmath>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Common.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
static int s_nMaxPixelInstructions;
|
|
||||||
static GLuint s_ColorMatrixProgram = 0;
|
|
||||||
static GLuint s_DepthMatrixProgram = 0;
|
|
||||||
PixelShaderCache::PSCache PixelShaderCache::pshaders;
|
|
||||||
PIXELSHADERUID PixelShaderCache::s_curuid;
|
|
||||||
bool PixelShaderCache::s_displayCompileAlert;
|
|
||||||
GLuint PixelShaderCache::CurrentShader;
|
|
||||||
bool PixelShaderCache::ShaderEnabled;
|
|
||||||
|
|
||||||
static FRAGMENTSHADER* pShaderLast = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
void PixelShaderCache::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);
|
|
||||||
//SetPSConstant4fv(const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f)
|
|
||||||
{
|
|
||||||
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; ++i, f+=4, ++const_number)
|
|
||||||
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
|
|
||||||
//SetPSConstant4fv(const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelShaderCache::PixelShaderCache()
|
|
||||||
{
|
|
||||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
||||||
ShaderEnabled = true;
|
|
||||||
CurrentShader = 0;
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid));
|
|
||||||
|
|
||||||
s_displayCompileAlert = true;
|
|
||||||
|
|
||||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
|
|
||||||
#if CG_VERSION_NUM == 2100
|
|
||||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
|
|
||||||
{
|
|
||||||
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[1024];
|
|
||||||
sprintf(pmatrixprog, "!!ARBfp1.0"
|
|
||||||
"TEMP R0;\n"
|
|
||||||
"TEMP R1;\n"
|
|
||||||
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
|
|
||||||
"DP4 R1.w, R0, program.env[%d];\n"
|
|
||||||
"DP4 R1.z, R0, program.env[%d];\n"
|
|
||||||
"DP4 R1.x, R0, program.env[%d];\n"
|
|
||||||
"DP4 R1.y, R0, program.env[%d];\n"
|
|
||||||
"ADD result.color, R1, program.env[%d];\n"
|
|
||||||
"END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, 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"
|
|
||||||
"TEMP R0;\n"
|
|
||||||
"TEMP R1;\n"
|
|
||||||
"TEMP R2;\n"
|
|
||||||
"PARAM K0 = { 65535.0, 255.0,1.0,16777215.0};\n"
|
|
||||||
"PARAM K1 = { 0.999999940395355224609375, 1.0000000596046483281045155587504,0.0,0.0};\n"
|
|
||||||
"TEX R2, fragment.texcoord[0], texture[0], RECT;\n"
|
|
||||||
"MUL R0, R2.x, K1.x;\n"
|
|
||||||
"MUL R0, R0.x, K0;\n"
|
|
||||||
"FRC R0, R0;\n"
|
|
||||||
"MUL R0, R0, K1.y;\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, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelShaderCache::~PixelShaderCache()
|
|
||||||
{
|
|
||||||
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
|
|
||||||
s_ColorMatrixProgram = 0;
|
|
||||||
glDeleteProgramsARB(1, &s_DepthMatrixProgram);
|
|
||||||
s_DepthMatrixProgram = 0;
|
|
||||||
PSCache::iterator iter = pshaders.begin();
|
|
||||||
for (; iter != pshaders.end(); iter++)
|
|
||||||
iter->second.Destroy();
|
|
||||||
pshaders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint PixelShaderCache::GetColorMatrixProgram()
|
|
||||||
{
|
|
||||||
return s_ColorMatrixProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint PixelShaderCache::GetDepthMatrixProgram()
|
|
||||||
{
|
|
||||||
return s_DepthMatrixProgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PixelShaderCache::SetShader(bool dstAlphaEnable)
|
|
||||||
{
|
|
||||||
const FRAGMENTSHADER* const ps = GetShader(dstAlphaEnable);
|
|
||||||
if (ps)
|
|
||||||
{
|
|
||||||
SetCurrentShader(ps->glprogid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRAGMENTSHADER* PixelShaderCache::GetShader(bool dstAlphaEnable)
|
|
||||||
{
|
|
||||||
DVSTARTPROFILE();
|
|
||||||
PIXELSHADERUID uid;
|
|
||||||
GetPixelShaderId(&uid, dstAlphaEnable ? 1 : 0);
|
|
||||||
if (uid == last_pixel_shader_uid && pshaders[uid].frameCount == frameCount)
|
|
||||||
{
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
|
|
||||||
|
|
||||||
PSCache::iterator iter = pshaders.find(uid);
|
|
||||||
|
|
||||||
if (iter != pshaders.end()) {
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
PSCacheEntry &entry = iter->second;
|
|
||||||
if (&entry.shader != pShaderLast)
|
|
||||||
{
|
|
||||||
pShaderLast = &entry.shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Make an entry in the table
|
|
||||||
PSCacheEntry& newentry = pshaders[uid];
|
|
||||||
newentry.frameCount = frameCount;
|
|
||||||
pShaderLast = &newentry.shader;
|
|
||||||
const char *code = GeneratePixelShaderCode(dstAlphaEnable,API_OPENGL);
|
|
||||||
|
|
||||||
#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), counter++);
|
|
||||||
|
|
||||||
SaveData(szTemp, code);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// printf("Compiling pixel shader. size = %i\n", strlen(code));
|
|
||||||
if (!code || !CompilePixelShader(newentry.shader, code)) {
|
|
||||||
ERROR_LOG(VIDEO, "failed to create pixel shader");
|
|
||||||
static int counter = 0;
|
|
||||||
char szTemp[MAX_PATH];
|
|
||||||
sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++);
|
|
||||||
SaveData(szTemp, code);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
INCSTAT(stats.numPixelShadersCreated);
|
|
||||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
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=32,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);
|
|
||||||
ERROR_LOG(VIDEO, "Failed to compile ps %s:", cgGetLastListing(g_cgcontext));
|
|
||||||
ERROR_LOG(VIDEO, pstrprogram);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle warnings
|
|
||||||
if (cgGetError() != CG_NO_ERROR)
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext));
|
|
||||||
WARN_LOG(VIDEO, 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, pstrprogram);
|
|
||||||
ERROR_LOG(VIDEO, pcompiledprog);
|
|
||||||
}
|
|
||||||
|
|
||||||
cgDestroyProgram(tempprog);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
ps.strprog = pstrprogram;
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,96 +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 _OGL_PIXELSHADERCACHE_H_
|
|
||||||
#define _OGL_PIXELSHADERCACHE_H_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "PixelShaderGen.h"
|
|
||||||
|
|
||||||
#include "../PixelShaderCache.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
struct FRAGMENTSHADER
|
|
||||||
{
|
|
||||||
FRAGMENTSHADER() : glprogid(0) { }
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
if (glprogid)
|
|
||||||
{
|
|
||||||
glDeleteProgramsARB(1, &glprogid);
|
|
||||||
glprogid = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GLuint glprogid; // opengl program id
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string strprog;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class PixelShaderCache : public ::PixelShaderCacheBase
|
|
||||||
{
|
|
||||||
struct PSCacheEntry
|
|
||||||
{
|
|
||||||
FRAGMENTSHADER shader;
|
|
||||||
int frameCount;
|
|
||||||
|
|
||||||
PSCacheEntry() : frameCount(0) {}
|
|
||||||
void Destroy()
|
|
||||||
{
|
|
||||||
shader.Destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
|
|
||||||
|
|
||||||
static PSCache pshaders;
|
|
||||||
static PIXELSHADERUID s_curuid; // the current pixel shader uid (progressively changed as memory is written)
|
|
||||||
static bool s_displayCompileAlert;
|
|
||||||
static GLuint CurrentShader;
|
|
||||||
static bool ShaderEnabled;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PixelShaderCache();
|
|
||||||
~PixelShaderCache();
|
|
||||||
|
|
||||||
static FRAGMENTSHADER* GetShader(bool dstAlphaEnable);
|
|
||||||
static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram);
|
|
||||||
|
|
||||||
static GLuint GetColorMatrixProgram();
|
|
||||||
static GLuint GetDepthMatrixProgram();
|
|
||||||
|
|
||||||
bool SetShader(bool dstAlphaEnable);
|
|
||||||
|
|
||||||
static void SetCurrentShader(GLuint Shader);
|
|
||||||
static void DisableShader();
|
|
||||||
|
|
||||||
void Clear() {}
|
|
||||||
|
|
||||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetPSConstant4fv(unsigned int const_number, const float *f);
|
|
||||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _PIXELSHADERCACHE_H_
|
|
|
@ -1,97 +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/
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_PostProcessing.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace PostProcessing
|
|
||||||
{
|
|
||||||
|
|
||||||
static std::string s_currentShader;
|
|
||||||
static FRAGMENTSHADER s_shader;
|
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
s_currentShader = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
s_shader.Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReloadShader()
|
|
||||||
{
|
|
||||||
s_currentShader = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApplyShader()
|
|
||||||
{
|
|
||||||
if (s_currentShader != std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt")
|
|
||||||
{
|
|
||||||
// Set immediately to prevent endless recompiles on failure.
|
|
||||||
if (!g_ActiveConfig.sPostProcessingShader.empty())
|
|
||||||
s_currentShader = std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt";
|
|
||||||
else
|
|
||||||
s_currentShader.clear();
|
|
||||||
|
|
||||||
s_shader.Destroy();
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_shader.glprogid != 0)
|
|
||||||
{
|
|
||||||
PixelShaderCache::SetCurrentShader(s_shader.glprogid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PixelShaderCache::DisableShader();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,42 +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 _OGL_POSTPROCESSING_H_
|
|
||||||
#define _OGL_POSTPROCESSING_H_
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace PostProcessing
|
|
||||||
{
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void ReloadShader();
|
|
||||||
// Returns false if no shader was applied.
|
|
||||||
bool ApplyShader();
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _POSTPROCESSING_H_
|
|
|
@ -1,226 +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 <string.h>
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_RasterFont.h"
|
|
||||||
// globals
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
GLubyte rasters[][13] = {
|
|
||||||
{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},
|
|
||||||
{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18},
|
|
||||||
{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70},
|
|
||||||
{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e},
|
|
||||||
{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c},
|
|
||||||
{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03},
|
|
||||||
{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c},
|
|
||||||
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18},
|
|
||||||
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60},
|
|
||||||
{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e},
|
|
||||||
{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
|
|
||||||
{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
|
|
||||||
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
|
|
||||||
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
|
|
||||||
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
|
|
||||||
{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
|
|
||||||
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
|
|
||||||
{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
|
|
||||||
{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
|
|
||||||
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
|
|
||||||
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
|
|
||||||
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
|
|
||||||
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
|
|
||||||
{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
|
|
||||||
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
|
|
||||||
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff},
|
|
||||||
{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c},
|
|
||||||
{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60},
|
|
||||||
{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18},
|
|
||||||
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70},
|
|
||||||
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
|
|
||||||
{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03},
|
|
||||||
{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e},
|
|
||||||
{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0},
|
|
||||||
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},
|
|
||||||
{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00},
|
|
||||||
{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0},
|
|
||||||
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78},
|
|
||||||
{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00},
|
|
||||||
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f},
|
|
||||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
|
|
||||||
{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0},
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
|
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
temp_buffer = new char[TEMP_BUFFER_SIZE];
|
|
||||||
}
|
|
||||||
|
|
||||||
RasterFont::~RasterFont()
|
|
||||||
{
|
|
||||||
glDeleteLists(fontOffset, 128);
|
|
||||||
delete [] temp_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterFont::printString(const char *s, double x, double y, double z)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
x = start_x;
|
|
||||||
t = temp;
|
|
||||||
}
|
|
||||||
else if (*text == '\r')
|
|
||||||
{
|
|
||||||
t = temp;
|
|
||||||
}
|
|
||||||
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 (t != text)
|
|
||||||
{
|
|
||||||
*t = 0;
|
|
||||||
printString(temp, x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,51 +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 _OGL_RASTERFONT_H_
|
|
||||||
#define _OGL_RASTERFONT_H_
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
class RasterFont {
|
|
||||||
public:
|
|
||||||
RasterFont();
|
|
||||||
~RasterFont(void);
|
|
||||||
static int debug;
|
|
||||||
|
|
||||||
// some useful constants
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
char_width = 10,
|
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int fontOffset;
|
|
||||||
char *temp_buffer;
|
|
||||||
enum {TEMP_BUFFER_SIZE = 64 * 1024};
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _RASTERFONT_H_
|
|
|
@ -1,985 +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 <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <mmsystem.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
//#include "OS/Win32.h"
|
|
||||||
//#include "AVIDump.h"
|
|
||||||
|
|
||||||
#include <wx/image.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
|
||||||
#include <wx/image.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "Thread.h"
|
|
||||||
#include "Atomic.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
#include "CommonPaths.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
#include "StringUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "DLCache.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VertexLoaderManager.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "OnScreenDisplay.h"
|
|
||||||
#include "Fifo.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_TextureCache.h"
|
|
||||||
#include "OGL_RasterFont.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
#include "OGL_VertexShaderCache.h"
|
|
||||||
#include "OGL_PostProcessing.h"
|
|
||||||
#include "OGL_TextureConverter.h"
|
|
||||||
#include "OGL_FramebufferManager.h"
|
|
||||||
#include "OGL_XFB.h"
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// Declarations and definitions
|
|
||||||
// ----------------------------
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
CGcontext g_cgcontext;
|
|
||||||
CGprofile g_cgvProf;
|
|
||||||
CGprofile g_cgfProf;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RasterFont* s_pfont = NULL;
|
|
||||||
|
|
||||||
static bool s_bLastFrameDumped = false;
|
|
||||||
#ifdef _WIN32
|
|
||||||
static bool s_bAVIDumping = false;
|
|
||||||
#else
|
|
||||||
static FILE* f_pFrameDump;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
|
|
||||||
static int s_MSAASamples = 1;
|
|
||||||
static int s_MSAACoverageSamples = 0;
|
|
||||||
|
|
||||||
bool s_bHaveFramebufferBlit = false; // export to FramebufferManager.cpp
|
|
||||||
static bool s_bHaveCoverageMSAA = false;
|
|
||||||
|
|
||||||
// The custom resolution
|
|
||||||
|
|
||||||
static bool s_skipSwap = false;
|
|
||||||
|
|
||||||
// TODO: EmuWindow has these too, merge them
|
|
||||||
int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0;
|
|
||||||
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
|
||||||
// Screenshot thread struct
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int W, H;
|
|
||||||
std::string filename;
|
|
||||||
wxImage *img;
|
|
||||||
} ScrStrct;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const GLenum glSrcFactors[8] =
|
|
||||||
{
|
|
||||||
GL_ZERO,
|
|
||||||
GL_ONE,
|
|
||||||
GL_DST_COLOR,
|
|
||||||
GL_ONE_MINUS_DST_COLOR,
|
|
||||||
GL_SRC_ALPHA,
|
|
||||||
GL_ONE_MINUS_SRC_ALPHA,
|
|
||||||
GL_DST_ALPHA,
|
|
||||||
GL_ONE_MINUS_DST_ALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLenum glDestFactors[8] = {
|
|
||||||
GL_ZERO,
|
|
||||||
GL_ONE,
|
|
||||||
GL_SRC_COLOR,
|
|
||||||
GL_ONE_MINUS_SRC_COLOR,
|
|
||||||
GL_SRC_ALPHA,
|
|
||||||
GL_ONE_MINUS_SRC_ALPHA,
|
|
||||||
GL_DST_ALPHA,
|
|
||||||
GL_ONE_MINUS_DST_ALPHA
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLenum glCmpFuncs[8] = {
|
|
||||||
GL_NEVER,
|
|
||||||
GL_LESS,
|
|
||||||
GL_EQUAL,
|
|
||||||
GL_LEQUAL,
|
|
||||||
GL_GREATER,
|
|
||||||
GL_NOTEQUAL,
|
|
||||||
GL_GEQUAL,
|
|
||||||
GL_ALWAYS
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLenum glLogicOpCodes[16] = {
|
|
||||||
GL_CLEAR,
|
|
||||||
GL_AND,
|
|
||||||
GL_AND_REVERSE,
|
|
||||||
GL_COPY,
|
|
||||||
GL_AND_INVERTED,
|
|
||||||
GL_NOOP,
|
|
||||||
GL_XOR,
|
|
||||||
GL_OR,
|
|
||||||
GL_NOR,
|
|
||||||
GL_EQUIV,
|
|
||||||
GL_INVERT,
|
|
||||||
GL_OR_REVERSE,
|
|
||||||
GL_COPY_INVERTED,
|
|
||||||
GL_OR_INVERTED,
|
|
||||||
GL_NAND,
|
|
||||||
GL_SET
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
void HandleCgError(CGcontext ctx, CGerror err, void* appdata)
|
|
||||||
{
|
|
||||||
DEBUG_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err));
|
|
||||||
const char* listing = cgGetLastListing(g_cgcontext);
|
|
||||||
if (listing != NULL)
|
|
||||||
DEBUG_LOG(VIDEO, " last listing: %s", listing);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Init functions
|
|
||||||
Renderer::Renderer()
|
|
||||||
{
|
|
||||||
// hmm
|
|
||||||
if (!OpenGL_Create(g_VideoInitialize, 640, 480))
|
|
||||||
{
|
|
||||||
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGL_MakeCurrent();
|
|
||||||
|
|
||||||
//if (!Renderer::Init()) {
|
|
||||||
// g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
|
|
||||||
// PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info");
|
|
||||||
// exit(1);
|
|
||||||
//}
|
|
||||||
|
|
||||||
bool bSuccess = true;
|
|
||||||
s_MSAACoverageSamples = 0;
|
|
||||||
GLint numvertexattribs = 0;
|
|
||||||
|
|
||||||
switch (g_ActiveConfig.iMultisampleMode)
|
|
||||||
{
|
|
||||||
case MULTISAMPLE_OFF:
|
|
||||||
s_MSAASamples = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_2X:
|
|
||||||
s_MSAASamples = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_4X:
|
|
||||||
s_MSAASamples = 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_8X:
|
|
||||||
s_MSAASamples = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_CSAA_8X:
|
|
||||||
s_MSAASamples = 4; s_MSAACoverageSamples = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_CSAA_8XQ:
|
|
||||||
s_MSAASamples = 8; s_MSAACoverageSamples = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_CSAA_16X:
|
|
||||||
s_MSAASamples = 4; s_MSAACoverageSamples = 16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MULTISAMPLE_CSAA_16XQ:
|
|
||||||
s_MSAASamples = 8; s_MSAACoverageSamples = 16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
s_MSAASamples = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
g_cgcontext = cgCreateContext();
|
|
||||||
cgGetError();
|
|
||||||
cgSetErrorHandler(HandleCgError, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Look for required extensions.
|
|
||||||
const char *const ptoken = (const char*)glGetString(GL_EXTENSIONS);
|
|
||||||
if (!ptoken)
|
|
||||||
{
|
|
||||||
PanicAlert("Your OpenGL Driver seems to be not working.\n"
|
|
||||||
"Please make sure your drivers are up-to-date and\n"
|
|
||||||
"that your video hardware is OpenGL 2.x compatible.");
|
|
||||||
//return false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
INFO_LOG(VIDEO, "Supported OpenGL Extensions:");
|
|
||||||
INFO_LOG(VIDEO, ptoken); // write to the log file
|
|
||||||
INFO_LOG(VIDEO, "");
|
|
||||||
|
|
||||||
OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s",
|
|
||||||
glGetString(GL_VENDOR),
|
|
||||||
glGetString(GL_RENDERER),
|
|
||||||
glGetString(GL_VERSION)).c_str(), 5000);
|
|
||||||
|
|
||||||
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs);
|
|
||||||
if (numvertexattribs < 11)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
|
|
||||||
"GPU: Does your video card support OpenGL 2.x?",
|
|
||||||
numvertexattribs);
|
|
||||||
bSuccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init extension support.
|
|
||||||
if (glewInit() != GLEW_OK)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?");
|
|
||||||
//return false;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLEW_EXT_framebuffer_object)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets.\n"
|
|
||||||
"GPU: Does your video card support OpenGL 2.x?");
|
|
||||||
bSuccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLEW_EXT_secondary_color)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n"
|
|
||||||
"GPU: Does your video card support OpenGL 2.x?");
|
|
||||||
bSuccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_bHaveFramebufferBlit = strstr(ptoken, "GL_EXT_framebuffer_blit") != NULL;
|
|
||||||
if (!s_bHaveFramebufferBlit)
|
|
||||||
{
|
|
||||||
// MSAA ain't gonna work. turn it off if enabled.
|
|
||||||
s_MSAASamples = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_bHaveCoverageMSAA = strstr(ptoken, "GL_NV_framebuffer_multisample_coverage") != NULL;
|
|
||||||
if (!s_bHaveCoverageMSAA)
|
|
||||||
{
|
|
||||||
s_MSAACoverageSamples = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bSuccess)
|
|
||||||
//return false;
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Handle VSync on/off
|
|
||||||
#if defined USE_WX && USE_WX
|
|
||||||
// TODO: FILL IN
|
|
||||||
#elif defined _WIN32
|
|
||||||
if (WGLEW_EXT_swap_control)
|
|
||||||
wglSwapIntervalEXT(g_ActiveConfig.bVSync ? 1 : 0);
|
|
||||||
else
|
|
||||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
|
||||||
if (glXSwapIntervalSGI)
|
|
||||||
glXSwapIntervalSGI(g_ActiveConfig.bVSync ? 1 : 0);
|
|
||||||
else
|
|
||||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// check the max texture width and height
|
|
||||||
GLint max_texture_size;
|
|
||||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size);
|
|
||||||
if (max_texture_size < 1024)
|
|
||||||
ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.",
|
|
||||||
max_texture_size);
|
|
||||||
|
|
||||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
|
||||||
bSuccess = false;
|
|
||||||
|
|
||||||
if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers)
|
|
||||||
glDrawBuffers = glDrawBuffersARB;
|
|
||||||
|
|
||||||
if (!GLEW_ARB_texture_non_power_of_two)
|
|
||||||
WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported.");
|
|
||||||
|
|
||||||
// Decide frambuffer size
|
|
||||||
FramebufferSize((int)OpenGL_GetBackbufferWidth(), (int)OpenGL_GetBackbufferHeight());
|
|
||||||
|
|
||||||
// Because of the fixed framebuffer size we need to disable the resolution
|
|
||||||
// options while running
|
|
||||||
g_Config.bRunning = true;
|
|
||||||
|
|
||||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
|
||||||
bSuccess = false;
|
|
||||||
|
|
||||||
// Initialize the FramebufferManager
|
|
||||||
g_framebuffer_manager = new FramebufferManager(s_backbuffer_width,
|
|
||||||
s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples);
|
|
||||||
|
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
|
||||||
|
|
||||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
|
||||||
bSuccess = false;
|
|
||||||
|
|
||||||
s_pfont = new RasterFont();
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
// load the effect, find the best profiles (if any)
|
|
||||||
if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "arbvp1 not supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE)
|
|
||||||
{
|
|
||||||
ERROR_LOG(VIDEO, "arbfp1 not supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX);
|
|
||||||
g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
|
|
||||||
#if CG_VERSION_NUM == 2100
|
|
||||||
// A bug was introduced in Cg2.1's handling of very large profile option values
|
|
||||||
// so this will not work on ATI. ATI returns MAXINT = 2147483647 (0x7fffffff)
|
|
||||||
// which is correct in OpenGL but Cg fails to handle it properly. As a result
|
|
||||||
// -1 is used by Cg resulting (signedness incorrect) and compilation fails.
|
|
||||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") == NULL)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
cgGLSetOptimalOptions(g_cgvProf);
|
|
||||||
cgGLSetOptimalOptions(g_cgfProf);
|
|
||||||
}
|
|
||||||
#endif // HAVE_CG
|
|
||||||
|
|
||||||
int nenvvertparams, nenvfragparams, naddrregisters[2];
|
|
||||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB,
|
|
||||||
GL_MAX_PROGRAM_ENV_PARAMETERS_ARB,
|
|
||||||
(GLint *)&nenvvertparams);
|
|
||||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
|
|
||||||
GL_MAX_PROGRAM_ENV_PARAMETERS_ARB,
|
|
||||||
(GLint *)&nenvfragparams);
|
|
||||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB,
|
|
||||||
GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB,
|
|
||||||
(GLint *)&naddrregisters[0]);
|
|
||||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
|
|
||||||
GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB,
|
|
||||||
(GLint *)&naddrregisters[1]);
|
|
||||||
DEBUG_LOG(VIDEO, "Max program env parameters: vert=%d, frag=%d",
|
|
||||||
nenvvertparams, nenvfragparams);
|
|
||||||
DEBUG_LOG(VIDEO, "Max program address register parameters: vert=%d, frag=%d",
|
|
||||||
naddrregisters[0], naddrregisters[1]);
|
|
||||||
|
|
||||||
if (nenvvertparams < 238)
|
|
||||||
ERROR_LOG(VIDEO, "Not enough vertex shader environment constants!!");
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
INFO_LOG(VIDEO, "Max buffer sizes: %d %d",
|
|
||||||
cgGetProgramBufferMaxSize(g_cgvProf),
|
|
||||||
cgGetProgramBufferMaxSize(g_cgfProf));
|
|
||||||
#ifndef _DEBUG
|
|
||||||
cgGLSetDebugMode(GL_FALSE);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
glStencilFunc(GL_ALWAYS, 0, 0);
|
|
||||||
glBlendFunc(GL_ONE, GL_ONE);
|
|
||||||
|
|
||||||
glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glShadeModel(GL_SMOOTH);
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
||||||
glClearDepth(1.0f);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
|
||||||
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
|
|
||||||
glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
|
|
||||||
glBlendColorEXT(0, 0, 0, 0.5f);
|
|
||||||
glClearDepth(1.0f);
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
// legacy multitexturing: select texture channel only.
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glClientActiveTexture(GL_TEXTURE0);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
|
|
||||||
UpdateActiveConfig();
|
|
||||||
//return GL_REPORT_ERROR() == GL_NO_ERROR && bSuccess;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Renderer::~Renderer()
|
|
||||||
{
|
|
||||||
g_Config.bRunning = false;
|
|
||||||
UpdateActiveConfig();
|
|
||||||
delete s_pfont;
|
|
||||||
s_pfont = 0;
|
|
||||||
|
|
||||||
#if defined HAVE_CG && HAVE_CG
|
|
||||||
if (g_cgcontext)
|
|
||||||
{
|
|
||||||
cgDestroyContext(g_cgcontext);
|
|
||||||
g_cgcontext = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
|
|
||||||
//#ifdef _WIN32
|
|
||||||
// if(s_bAVIDumping)
|
|
||||||
// AVIDump::Stop();
|
|
||||||
//#else
|
|
||||||
// if(f_pFrameDump != NULL)
|
|
||||||
// fclose(f_pFrameDump);
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
OpenGL_Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the OSD menu's live resolution change
|
|
||||||
bool Renderer::Allow2x()
|
|
||||||
{
|
|
||||||
if (GetFrameBufferWidth() >= 1280 && GetFrameBufferHeight() >= 960)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::AllowCustom()
|
|
||||||
{
|
|
||||||
//if (GetCustomWidth() <= GetFrameBufferWidth() && GetCustomHeight() <= GetFrameBufferHeight())
|
|
||||||
// return true;
|
|
||||||
//else
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::ResetAPIState()
|
|
||||||
{
|
|
||||||
// Gets us to a reasonably sane state where it's possible to do things like
|
|
||||||
// image copies with textured quads, etc.
|
|
||||||
VertexShaderCache::DisableShader();
|
|
||||||
PixelShaderCache::DisableShader();
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateViewport();
|
|
||||||
|
|
||||||
void Renderer::RestoreAPIState()
|
|
||||||
{
|
|
||||||
// Gets us back into a more game-like state.
|
|
||||||
|
|
||||||
UpdateViewport();
|
|
||||||
|
|
||||||
if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
|
|
||||||
if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
|
|
||||||
if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
|
|
||||||
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
SetScissorRect();
|
|
||||||
SetColorMask();
|
|
||||||
SetBlendMode(true);
|
|
||||||
|
|
||||||
VertexShaderCache::SetCurrentShader(0);
|
|
||||||
PixelShaderCache::SetCurrentShader(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetColorMask()
|
|
||||||
{
|
|
||||||
GLenum ColorMask = (bpmem.blendmode.colorupdate) ? GL_TRUE : GL_FALSE;
|
|
||||||
GLenum AlphaMask = (bpmem.blendmode.alphaupdate) ? GL_TRUE : GL_FALSE;
|
|
||||||
glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
|
||||||
{
|
|
||||||
// blend mode bit mask
|
|
||||||
// 0 - blend enable
|
|
||||||
// 2 - reverse subtract enable (else add)
|
|
||||||
// 3-5 - srcRGB function
|
|
||||||
// 6-8 - dstRGB function
|
|
||||||
|
|
||||||
u32 newval = bpmem.blendmode.subtract << 2;
|
|
||||||
|
|
||||||
if (bpmem.blendmode.subtract)
|
|
||||||
newval |= 0x0049; // enable blending src 1 dst 1
|
|
||||||
else if (bpmem.blendmode.blendenable)
|
|
||||||
{
|
|
||||||
newval |= 1; // enable blending
|
|
||||||
newval |= bpmem.blendmode.srcfactor << 3;
|
|
||||||
newval |= bpmem.blendmode.dstfactor << 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
|
|
||||||
|
|
||||||
if (changes & 1)
|
|
||||||
// blend enable change
|
|
||||||
(newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
|
||||||
|
|
||||||
if (changes & 4)
|
|
||||||
// subtract enable change
|
|
||||||
glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD);
|
|
||||||
|
|
||||||
if (changes & 0x1F8)
|
|
||||||
// blend RGB change
|
|
||||||
glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]);
|
|
||||||
|
|
||||||
s_blendMode = newval;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
|
||||||
{
|
|
||||||
if(!g_ActiveConfig.bEFBAccessEnable)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Get the rectangular target region covered by the EFB pixel.
|
|
||||||
EFBRectangle efbPixelRc;
|
|
||||||
efbPixelRc.left = x;
|
|
||||||
efbPixelRc.top = y;
|
|
||||||
efbPixelRc.right = x + 1;
|
|
||||||
efbPixelRc.bottom = y + 1;
|
|
||||||
|
|
||||||
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
|
|
||||||
|
|
||||||
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
|
|
||||||
case PEEK_Z:
|
|
||||||
{
|
|
||||||
if (s_MSAASamples > 1)
|
|
||||||
{
|
|
||||||
// Resolve our rectangle.
|
|
||||||
FramebufferManager::GetEFBDepthTexture(efbPixelRc);
|
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample from the center of the target region.
|
|
||||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
|
||||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
|
||||||
|
|
||||||
u32 z = 0;
|
|
||||||
glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// Scale the 32-bit value returned by glReadPixels to a 24-bit
|
|
||||||
// value (GC uses a 24-bit Z-buffer).
|
|
||||||
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
|
|
||||||
return z >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
case POKE_Z:
|
|
||||||
// TODO: Implement
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PEEK_COLOR: // GXPeekARGB
|
|
||||||
{
|
|
||||||
// Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
|
|
||||||
|
|
||||||
// Tested in Killer 7, the first 8bits represent the alpha value which is used to
|
|
||||||
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
|
|
||||||
// Wind Waker is also using it for the pictograph to determine the color of each pixel
|
|
||||||
|
|
||||||
if (s_MSAASamples > 1)
|
|
||||||
{
|
|
||||||
// Resolve our rectangle.
|
|
||||||
FramebufferManager::GetEFBColorTexture(efbPixelRc);
|
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sample from the center of the target region.
|
|
||||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
|
||||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
|
||||||
|
|
||||||
// Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format.
|
|
||||||
u32 color = 0;
|
|
||||||
glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
case POKE_COLOR:
|
|
||||||
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
|
|
||||||
// the exact location. Note: EFB pokes are susceptible to Z-buffering
|
|
||||||
// and perhaps blending.
|
|
||||||
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function: This function handles the OpenGL glScissor() function
|
|
||||||
// ----------------------------
|
|
||||||
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
|
|
||||||
// case 0x52 > SetScissorRect()
|
|
||||||
// ----------------------------
|
|
||||||
// bpmem.scissorTL.x, y = 342x342
|
|
||||||
// bpmem.scissorBR.x, y = 981x821
|
|
||||||
// GetTargetHeight() = the fixed ini file setting
|
|
||||||
// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
|
|
||||||
// therefore the width and height are (scissorBR + 1) - scissorTL
|
|
||||||
bool Renderer::SetScissorRect()
|
|
||||||
{
|
|
||||||
EFBRectangle rc;
|
|
||||||
if (g_renderer->SetScissorRect(rc))
|
|
||||||
{
|
|
||||||
glScissor(
|
|
||||||
(int)(rc.left * EFBxScale), // x = 0 for example
|
|
||||||
(int)((EFB_HEIGHT - rc.bottom) * EFByScale), // y = 0 for example
|
|
||||||
(int)((rc.right - rc.left) * EFBxScale), // width = 640 for example
|
|
||||||
(int)((rc.bottom - rc.top) * EFByScale) // height = 480 for example
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable,
|
|
||||||
bool alphaEnable, bool zEnable, u32 color, u32 z)
|
|
||||||
{
|
|
||||||
// Update the view port for clearing the picture
|
|
||||||
TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
|
||||||
glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
|
||||||
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
|
||||||
|
|
||||||
// Always set the scissor in case it was set by the game and has not been reset
|
|
||||||
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
|
|
||||||
GLbitfield bits = 0;
|
|
||||||
if (colorEnable)
|
|
||||||
{
|
|
||||||
bits |= GL_COLOR_BUFFER_BIT;
|
|
||||||
glClearColor(
|
|
||||||
((color >> 16) & 0xFF) / 255.0f,
|
|
||||||
((color >> 8) & 0xFF) / 255.0f,
|
|
||||||
(color & 0xFF) / 255.0f,
|
|
||||||
((color >> 24) & 0xFF) / 255.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (zEnable)
|
|
||||||
{
|
|
||||||
bits |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
|
||||||
glClear(bits);
|
|
||||||
SetScissorRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect)
|
|
||||||
{
|
|
||||||
// Update GLViewPort
|
|
||||||
glViewport(dst_rect.left, dst_rect.bottom, dst_rect.GetWidth(), dst_rect.GetHeight());
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// Copy the framebuffer to screen.
|
|
||||||
|
|
||||||
// Texture map s_xfbTexture onto the main buffer
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
|
||||||
// Use linear filtering.
|
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc)
|
|
||||||
{
|
|
||||||
// testing
|
|
||||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
||||||
|
|
||||||
if (xfbSource)
|
|
||||||
{
|
|
||||||
// Texture map xfbSource->texture onto the main buffer
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ((XFBSource*)xfbSource)->texture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Render to the real buffer now.
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, FramebufferManager::ResolveAndGetRenderTarget(rc));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must call ApplyShader here even if no post proc is selected - it takes
|
|
||||||
// care of disabling it in that case. It returns false in case of no post processing.
|
|
||||||
bool applyShader = PostProcessing::ApplyShader();
|
|
||||||
if (applyShader)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
PixelShaderCache::DisableShader();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glTexCoord2f(sourceRc.left, sourceRc.bottom);
|
|
||||||
glVertex2f(drawRc.left, drawRc.bottom);
|
|
||||||
|
|
||||||
glTexCoord2f(sourceRc.left, sourceRc.top);
|
|
||||||
glVertex2f(drawRc.left, drawRc.top);
|
|
||||||
|
|
||||||
glTexCoord2f(sourceRc.right, sourceRc.top);
|
|
||||||
glVertex2f(drawRc.right, drawRc.top);
|
|
||||||
|
|
||||||
glTexCoord2f(sourceRc.right, sourceRc.bottom);
|
|
||||||
glVertex2f(drawRc.right, drawRc.bottom);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
TextureCache::DisableStage(0);
|
|
||||||
|
|
||||||
// TODO: silly place for this
|
|
||||||
// Wireframe
|
|
||||||
if (g_ActiveConfig.bWireFrame)
|
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::EndFrame()
|
|
||||||
{
|
|
||||||
// Copy the rendered frame to the real window
|
|
||||||
OpenGL_SwapBuffers();
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// Clear framebuffer
|
|
||||||
glClearColor(0, 0, 0, 0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Present()
|
|
||||||
{
|
|
||||||
// Render to the framebuffer.
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Renderer::CheckForResize()
|
|
||||||
{
|
|
||||||
// TODO: temp
|
|
||||||
|
|
||||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::GetBackBufferSize(int* w, int* h)
|
|
||||||
{
|
|
||||||
*w = (int)OpenGL_GetBackbufferWidth();
|
|
||||||
*h = (int)OpenGL_GetBackbufferHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RecreateFramebufferManger()
|
|
||||||
{
|
|
||||||
delete g_framebuffer_manager;
|
|
||||||
g_framebuffer_manager = new FramebufferManager(s_backbuffer_width,
|
|
||||||
s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples);
|
|
||||||
|
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::BeginFrame()
|
|
||||||
{
|
|
||||||
// TODO: silly place for this
|
|
||||||
g_Config.iSaveTargetId = 0;
|
|
||||||
|
|
||||||
bool last_copy_efb_to_Texture = g_ActiveConfig.bCopyEFBToTexture;
|
|
||||||
UpdateActiveConfig();
|
|
||||||
if (last_copy_efb_to_Texture != g_ActiveConfig.bCopyEFBToTexture)
|
|
||||||
TextureCache::ClearRenderTargets();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from VertexShaderManager
|
|
||||||
void Renderer::UpdateViewport()
|
|
||||||
{
|
|
||||||
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
|
|
||||||
// [0] = width/2
|
|
||||||
// [1] = height/2
|
|
||||||
// [2] = 16777215 * (farz - nearz)
|
|
||||||
// [3] = xorig + width/2 + 342
|
|
||||||
// [4] = yorig + height/2 + 342
|
|
||||||
// [5] = 16777215 * farz
|
|
||||||
float scissorXOff = float(bpmem.scissorOffset.x) * 2.0f; // 342
|
|
||||||
float scissorYOff = float(bpmem.scissorOffset.y) * 2.0f; // 342
|
|
||||||
|
|
||||||
// Stretch picture with increased internal resolution
|
|
||||||
int GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - scissorXOff) *
|
|
||||||
EFBxScale);
|
|
||||||
int GLy = (int)ceil(
|
|
||||||
(float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + scissorYOff) *
|
|
||||||
EFByScale);
|
|
||||||
int GLWidth = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale);
|
|
||||||
int GLHeight = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale);
|
|
||||||
double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
|
|
||||||
double GLFar = xfregs.rawViewport[5] / 16777216.0f;
|
|
||||||
if(GLWidth < 0)
|
|
||||||
{
|
|
||||||
GLx += GLWidth;
|
|
||||||
GLWidth*=-1;
|
|
||||||
}
|
|
||||||
if(GLHeight < 0)
|
|
||||||
{
|
|
||||||
GLy += GLHeight;
|
|
||||||
GLHeight *= -1;
|
|
||||||
}
|
|
||||||
// Update the view port
|
|
||||||
glViewport(GLx, GLy, GLWidth, GLHeight);
|
|
||||||
glDepthRange(GLNear, GLFar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetGenerationMode()
|
|
||||||
{
|
|
||||||
// none, ccw, cw, ccw
|
|
||||||
if (bpmem.genMode.cullmode > 0)
|
|
||||||
{
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDepthMode()
|
|
||||||
{
|
|
||||||
if (bpmem.zmode.testenable)
|
|
||||||
{
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE);
|
|
||||||
glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if the test is disabled write is disabled too
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetLogicOpMode()
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
|
||||||
{
|
|
||||||
glEnable(GL_COLOR_LOGIC_OP);
|
|
||||||
glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
glDisable(GL_COLOR_LOGIC_OP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetDitherMode()
|
|
||||||
{
|
|
||||||
if (bpmem.blendmode.dither)
|
|
||||||
glEnable(GL_DITHER);
|
|
||||||
else
|
|
||||||
glDisable(GL_DITHER);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::SetLineWidth()
|
|
||||||
{
|
|
||||||
float fratio = xfregs.rawViewport[0] != 0 ?
|
|
||||||
((float)GetTargetWidth() / EFB_WIDTH) : 1.0f;
|
|
||||||
if (bpmem.lineptwidth.linesize > 0)
|
|
||||||
// scale by ratio of widths
|
|
||||||
glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f);
|
|
||||||
if (bpmem.lineptwidth.pointsize > 0)
|
|
||||||
glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
|
|
||||||
#ifndef _OGL_RENDER_H_
|
|
||||||
#define _OGL_RENDER_H_
|
|
||||||
|
|
||||||
#include "MathUtil.h"
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "pluginspecs_video.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
extern int OSDChoice;
|
|
||||||
|
|
||||||
class Renderer : public ::RendererBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Renderer();
|
|
||||||
~Renderer();
|
|
||||||
|
|
||||||
// What's the real difference between these? Too similar names.
|
|
||||||
void ResetAPIState();
|
|
||||||
void RestoreAPIState();
|
|
||||||
|
|
||||||
void SetColorMask();
|
|
||||||
void SetBlendMode(bool forceUpdate);
|
|
||||||
bool SetScissorRect();
|
|
||||||
void SetGenerationMode();
|
|
||||||
void SetDepthMode();
|
|
||||||
void SetLogicOpMode();
|
|
||||||
void SetDitherMode();
|
|
||||||
void SetLineWidth();
|
|
||||||
|
|
||||||
// Live resolution change
|
|
||||||
bool Allow2x();
|
|
||||||
bool AllowCustom();
|
|
||||||
|
|
||||||
u32 AccessEFB(EFBAccessType type, int x, int y);
|
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
|
||||||
void UpdateViewport();
|
|
||||||
|
|
||||||
// virtual funcs used by RendererBase::Swap
|
|
||||||
void PrepareXFBCopy(const TargetRectangle &dst_rect);
|
|
||||||
void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc);
|
|
||||||
void EndFrame();
|
|
||||||
void Present();
|
|
||||||
bool CheckForResize();
|
|
||||||
void GetBackBufferSize(int* w, int* h);
|
|
||||||
void RecreateFramebufferManger();
|
|
||||||
void BeginFrame();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,339 +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 <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
|
||||||
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
|
|
||||||
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
|
|
||||||
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
|
|
||||||
#include <intrin.h>
|
|
||||||
#undef _interlockedbittestandset
|
|
||||||
#undef _interlockedbittestandreset
|
|
||||||
#undef _interlockedbittestandset64
|
|
||||||
#undef _interlockedbittestandreset64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "CommonPaths.h"
|
|
||||||
#include "StringUtil.h"
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Hash.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "BPStructs.h"
|
|
||||||
#include "TextureDecoder.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "HiresTextures.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_TextureCache.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
#include "OGL_TextureConverter.h"
|
|
||||||
#include "OGL_FramebufferManager.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
TextureCache::TCacheEntry::~TCacheEntry()
|
|
||||||
{
|
|
||||||
if (texture)
|
|
||||||
{
|
|
||||||
glDeleteTextures(1, &texture);
|
|
||||||
texture = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntry::TCacheEntry()
|
|
||||||
{
|
|
||||||
glGenTextures(1, &texture);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int level)
|
|
||||||
{
|
|
||||||
if (bHaveMipMaps)
|
|
||||||
{
|
|
||||||
if (pcfmt != PC_TEX_FMT_DXT1)
|
|
||||||
{
|
|
||||||
if (expanded_width != (int)width)
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp);
|
|
||||||
|
|
||||||
if (expanded_width != (int)width)
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO:
|
|
||||||
//glCompressedTexImage2D(target, level, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, width, height, 0, expanded_width*expanded_height/2, temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
|
|
||||||
// Make sure to resolve anything we need to read from.
|
|
||||||
const GLuint read_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source_rect) : FramebufferManager::ResolveAndGetRenderTarget(source_rect);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
if (s_TempFramebuffer == 0)
|
|
||||||
glGenFramebuffersEXT(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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
glViewport(0, 0, Scaledw, Scaledh);
|
|
||||||
|
|
||||||
PixelShaderCache::SetCurrentShader(bFromZBuffer ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
|
|
||||||
const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat
|
|
||||||
PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect);
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// Unbind texture from temporary framebuffer
|
|
||||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
|
|
||||||
|
|
||||||
// TODO: these good here?
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
DisableStage(0);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// TODO: do this?
|
|
||||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
|
||||||
{
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
|
||||||
unsigned int height, unsigned int expanded_width,
|
|
||||||
unsigned int tex_levels, PC_TexFormat pcfmt)
|
|
||||||
{
|
|
||||||
TCacheEntry &entry = *new TCacheEntry;
|
|
||||||
|
|
||||||
int gl_format = 0;
|
|
||||||
int gl_iformat = 0;
|
|
||||||
int gl_type = 0;
|
|
||||||
|
|
||||||
if (pcfmt != PC_TEX_FMT_DXT1)
|
|
||||||
{
|
|
||||||
switch (pcfmt)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case PC_TEX_FMT_NONE:
|
|
||||||
PanicAlert("Invalid PC texture format %i", pcfmt);
|
|
||||||
case PC_TEX_FMT_BGRA32:
|
|
||||||
gl_format = GL_BGRA;
|
|
||||||
gl_iformat = 4;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_RGBA32:
|
|
||||||
gl_format = GL_RGBA;
|
|
||||||
gl_iformat = 4;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_I4_AS_I8:
|
|
||||||
gl_format = GL_LUMINANCE;
|
|
||||||
gl_iformat = GL_INTENSITY4;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_IA4_AS_IA8:
|
|
||||||
gl_format = GL_LUMINANCE_ALPHA;
|
|
||||||
gl_iformat = GL_LUMINANCE4_ALPHA4;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_I8:
|
|
||||||
gl_format = GL_LUMINANCE;
|
|
||||||
gl_iformat = GL_INTENSITY8;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_IA8:
|
|
||||||
gl_format = GL_LUMINANCE_ALPHA;
|
|
||||||
gl_iformat = GL_LUMINANCE8_ALPHA8;
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PC_TEX_FMT_RGB565:
|
|
||||||
gl_format = GL_RGB;
|
|
||||||
gl_iformat = GL_RGB;
|
|
||||||
gl_type = GL_UNSIGNED_SHORT_5_6_5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.gl_format = gl_format;
|
|
||||||
entry.gl_iformat = gl_iformat;
|
|
||||||
entry.gl_type = gl_type;
|
|
||||||
|
|
||||||
// ok?
|
|
||||||
//Load(width, height, expanded_width, level);
|
|
||||||
|
|
||||||
return &entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h)
|
|
||||||
{
|
|
||||||
TCacheEntry &entry = *new TCacheEntry;
|
|
||||||
|
|
||||||
entry.isDynamic = false;
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, entry.texture);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
const GLenum gl_format = GL_RGBA,
|
|
||||||
gl_iformat = 4,
|
|
||||||
gl_type = GL_UNSIGNED_BYTE;
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_w, 0, gl_format, gl_type, NULL);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1)
|
|
||||||
{
|
|
||||||
mode = newmode;
|
|
||||||
//mode1 = newmode1;
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
|
||||||
(newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
|
|
||||||
|
|
||||||
if (bHaveMipMaps)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCache::~TextureCache()
|
|
||||||
{
|
|
||||||
if (s_TempFramebuffer)
|
|
||||||
{
|
|
||||||
glDeleteFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer);
|
|
||||||
s_TempFramebuffer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCache::DisableStage(int stage)
|
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0 + stage);
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
glDisable(GL_TEXTURE_RECTANGLE_ARB);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +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 _OGL_TEXTURECACHE_H_
|
|
||||||
#define _OGL_TEXTURECACHE_H_
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
#include "../TextureCache.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
class TextureCache : public ::TextureCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct TCacheEntry : TCacheEntryBase
|
|
||||||
{
|
|
||||||
GLuint texture;
|
|
||||||
|
|
||||||
bool isDynamic;
|
|
||||||
bool bHaveMipMaps;
|
|
||||||
|
|
||||||
PC_TexFormat pcfmt;
|
|
||||||
|
|
||||||
int gl_format;
|
|
||||||
int gl_iformat;
|
|
||||||
int gl_type;
|
|
||||||
|
|
||||||
TexMode0 mode; // current filter and clamp modes that texture is set to
|
|
||||||
TexMode1 mode1; // current filter and clamp modes that texture is set to
|
|
||||||
|
|
||||||
void SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1);
|
|
||||||
|
|
||||||
TCacheEntry();
|
|
||||||
~TCacheEntry();
|
|
||||||
|
|
||||||
void Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int level);
|
|
||||||
|
|
||||||
void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect);
|
|
||||||
|
|
||||||
void Bind(unsigned int stage);
|
|
||||||
};
|
|
||||||
|
|
||||||
~TextureCache();
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
|
|
||||||
|
|
||||||
TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h);
|
|
||||||
|
|
||||||
void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source);
|
|
||||||
|
|
||||||
static void DisableStage(int stage); // sets active texture
|
|
||||||
};
|
|
||||||
|
|
||||||
//bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _TEXTUREMNGR_H_
|
|
|
@ -1,486 +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/
|
|
||||||
|
|
||||||
// Fast image conversion using OpenGL shaders.
|
|
||||||
// This kind of stuff would be a LOT nicer with OpenCL.
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "TextureConversionShader.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_TextureConverter.h"
|
|
||||||
#include "OGL_TextureCache.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
#include "OGL_FramebufferManager.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace TextureConverter
|
|
||||||
{
|
|
||||||
|
|
||||||
static GLuint s_texConvFrameBuffer = 0;
|
|
||||||
static GLuint s_srcTexture = 0; // for decoding from RAM
|
|
||||||
static GLuint s_srcTextureWidth = 0;
|
|
||||||
static GLuint s_srcTextureHeight = 0;
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Not all slots are taken - but who cares.
|
|
||||||
const u32 NUM_ENCODING_PROGRAMS = 64;
|
|
||||||
static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
|
||||||
|
|
||||||
void CreateRgbToYuyvProgram()
|
|
||||||
{
|
|
||||||
// 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";
|
|
||||||
|
|
||||||
if (!PixelShaderCache::CompilePixelShader(s_rgbToYuyvProgram, FProgram)) {
|
|
||||||
ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (format > NUM_ENCODING_PROGRAMS)
|
|
||||||
{
|
|
||||||
PanicAlert("Unknown texture copy format: 0x%x\n", format);
|
|
||||||
return s_encodingPrograms[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_encodingPrograms[format].glprogid == 0)
|
|
||||||
{
|
|
||||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_OPENGL);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) {
|
|
||||||
static int counter = 0;
|
|
||||||
char szTemp[MAX_PATH];
|
|
||||||
sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++);
|
|
||||||
|
|
||||||
SaveData(szTemp, shader);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!PixelShaderCache::CompilePixelShader(s_encodingPrograms[format], shader)) {
|
|
||||||
ERROR_LOG(VIDEO, "Failed to create encoding fragment program");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_encodingPrograms[format];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
glGenFramebuffersEXT(1, &s_texConvFrameBuffer);
|
|
||||||
|
|
||||||
glGenRenderbuffersEXT(1, &s_dstRenderBuffer);
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight);
|
|
||||||
|
|
||||||
glGenTextures(1, &s_srcTexture);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown()
|
|
||||||
{
|
|
||||||
glDeleteTextures(1, &s_srcTexture);
|
|
||||||
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
|
|
||||||
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
|
|
||||||
|
|
||||||
s_rgbToYuyvProgram.Destroy();
|
|
||||||
s_yuyvToRgbProgram.Destroy();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++)
|
|
||||||
s_encodingPrograms[i].Destroy();
|
|
||||||
|
|
||||||
s_srcTexture = 0;
|
|
||||||
s_dstRenderBuffer = 0;
|
|
||||||
s_texConvFrameBuffer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc,
|
|
||||||
u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
// switch to texture converter frame buffer
|
|
||||||
// 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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (linearFilter)
|
|
||||||
{
|
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);
|
|
||||||
|
|
||||||
PixelShaderCache::SetCurrentShader(shader.glprogid);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
// .. and then readback the results.
|
|
||||||
// TODO: make this less slow.
|
|
||||||
|
|
||||||
int writeStride = bpmem.copyMipMapStrideChannels * 32;
|
|
||||||
|
|
||||||
if (writeStride != readStride && toTexture)
|
|
||||||
{
|
|
||||||
// writing to a texture of a different size
|
|
||||||
|
|
||||||
int readHeight = readStride / dstWidth;
|
|
||||||
readHeight /= 4; // 4 bytes per pixel
|
|
||||||
|
|
||||||
int readStart = 0;
|
|
||||||
int readLoops = dstHeight / readHeight;
|
|
||||||
for (int i = 0; i < readLoops; i++)
|
|
||||||
{
|
|
||||||
glReadPixels(0, readStart, (GLsizei)dstWidth, (GLsizei)readHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
|
|
||||||
|
|
||||||
readStart += readHeight;
|
|
||||||
destAddr += writeStride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
|
||||||
{
|
|
||||||
u32 format = copyfmt;
|
|
||||||
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
format |= _GX_TF_ZTF;
|
|
||||||
if (copyfmt == 11)
|
|
||||||
format = GX_TF_Z16;
|
|
||||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
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;
|
|
||||||
|
|
||||||
u8 *dest_ptr = Memory_GetPtr(address);
|
|
||||||
|
|
||||||
GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source);
|
|
||||||
|
|
||||||
int width = (source.right - source.left) >> bScaleByHalf;
|
|
||||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
|
||||||
|
|
||||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
|
||||||
|
|
||||||
// Invalidate any existing texture covering this memory range.
|
|
||||||
// TODO - don't delete the texture if it already exists, just replace the contents.
|
|
||||||
TextureCache::InvalidateRange(address, size_in_bytes);
|
|
||||||
|
|
||||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
|
||||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
|
||||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
|
||||||
|
|
||||||
// only copy on cache line boundaries
|
|
||||||
// extra pixels are copied but not displayed in the resulting texture
|
|
||||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
|
||||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
|
||||||
|
|
||||||
float MValueX = Renderer::GetTargetScaleX();
|
|
||||||
float MValueY = Renderer::GetTargetScaleY();
|
|
||||||
|
|
||||||
float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ;
|
|
||||||
|
|
||||||
float sampleStride = bScaleByHalf?2.0f:1.0f;
|
|
||||||
|
|
||||||
TextureConversionShader::SetShaderParameters((float)expandedWidth,
|
|
||||||
expandedHeight * MValueY,
|
|
||||||
source.left * MValueX,
|
|
||||||
top,
|
|
||||||
sampleStride * MValueX,
|
|
||||||
sampleStride * MValueY);
|
|
||||||
|
|
||||||
TargetRectangle scaledSource;
|
|
||||||
scaledSource.top = 0;
|
|
||||||
scaledSource.bottom = expandedHeight;
|
|
||||||
scaledSource.left = 0;
|
|
||||||
scaledSource.right = expandedWidth / samples;
|
|
||||||
|
|
||||||
|
|
||||||
int cacheBytes = 32;
|
|
||||||
if ((format & 0x0f) == 6)
|
|
||||||
cacheBytes = 64;
|
|
||||||
|
|
||||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
|
||||||
g_renderer->ResetAPIState();
|
|
||||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0);
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
TextureCache::DisableStage(0);
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY,bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
|
||||||
{
|
|
||||||
u32 format = copyfmt;
|
|
||||||
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
format |= _GX_TF_ZTF;
|
|
||||||
if (copyfmt == 11)
|
|
||||||
format = GX_TF_Z16;
|
|
||||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
|
||||||
format |= _GX_TF_CTF;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
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;
|
|
||||||
|
|
||||||
u8 *dest_ptr = Memory_GetPtr(address);
|
|
||||||
|
|
||||||
int width = (source.right - source.left) >> bScaleByHalf;
|
|
||||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
|
||||||
|
|
||||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
|
||||||
|
|
||||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
|
||||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
|
||||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
|
||||||
|
|
||||||
// only copy on cache line boundaries
|
|
||||||
// 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.0f:1.0f;
|
|
||||||
float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ;
|
|
||||||
TextureConversionShader::SetShaderParameters((float)expandedWidth,
|
|
||||||
expandedHeight * MValueY,
|
|
||||||
source.left * MValueX,
|
|
||||||
top,
|
|
||||||
sampleStride * MValueX,
|
|
||||||
sampleStride * MValueY);
|
|
||||||
|
|
||||||
TargetRectangle scaledSource;
|
|
||||||
scaledSource.top = 0;
|
|
||||||
scaledSource.bottom = expandedHeight;
|
|
||||||
scaledSource.left = 0;
|
|
||||||
scaledSource.right = expandedWidth / samples;
|
|
||||||
|
|
||||||
|
|
||||||
int cacheBytes = 32;
|
|
||||||
if ((format & 0x0f) == 6)
|
|
||||||
cacheBytes = 64;
|
|
||||||
|
|
||||||
int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format);
|
|
||||||
|
|
||||||
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0 && !bFromZBuffer);
|
|
||||||
g_texture_cache->MakeRangeDynamic(address,size_in_bytes);
|
|
||||||
return GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
TextureCache::DisableStage(0);
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Should be scale free.
|
|
||||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture)
|
|
||||||
{
|
|
||||||
u8* srcAddr = Memory_GetPtr(xfbAddr);
|
|
||||||
if (!srcAddr)
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "Tried to decode from invalid memory address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_renderer->ResetAPIState();
|
|
||||||
|
|
||||||
int srcFmtWidth = srcWidth / 2;
|
|
||||||
|
|
||||||
// swich 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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// TODO: make this less slow. (How?)
|
|
||||||
if((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
|
|
||||||
{
|
|
||||||
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 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, 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);
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
|
||||||
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +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 _OGL_TEXTURECONVERTER_H_
|
|
||||||
#define _OGL_TEXTURECONVERTER_H_
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// Converts textures between formats
|
|
||||||
// TODO: support multiple texture formats
|
|
||||||
namespace TextureConverter
|
|
||||||
{
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
|
||||||
u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
|
||||||
|
|
||||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
|
||||||
u8* destAddr, int dstWidth, int dstHeight);
|
|
||||||
|
|
||||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
|
||||||
|
|
||||||
u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _TEXTURECONVERTER_H_
|
|
|
@ -1,113 +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 <fstream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "IndexGenerator.h"
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_TextureCache.h"
|
|
||||||
#include "OGL_PixelShaderCache.h"
|
|
||||||
#include "OGL_VertexShaderCache.h"
|
|
||||||
#include "OGL_VertexManager.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MAXVBUFFERSIZE = 0x1FFFF,
|
|
||||||
MAXIBUFFERSIZE = 0xFFFF,
|
|
||||||
MAXVBOBUFFERCOUNT = 0x8,
|
|
||||||
};
|
|
||||||
|
|
||||||
//static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0};
|
|
||||||
//static int s_nCurVBOIndex = 0; // current free buffer
|
|
||||||
|
|
||||||
VertexManager::VertexManager()
|
|
||||||
{
|
|
||||||
lastPrimitive = GX_DRAW_NONE;
|
|
||||||
|
|
||||||
//s_nCurVBOIndex = 0;
|
|
||||||
//glGenBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
g_nativeVertexFmt = NULL;
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexManager::~VertexManager()
|
|
||||||
{
|
|
||||||
//glDeleteBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers);
|
|
||||||
//s_nCurVBOIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManager::Draw(u32 /*stride*/, bool alphapass)
|
|
||||||
{
|
|
||||||
if (alphapass)
|
|
||||||
{
|
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IndexGenerator::GetNumTriangles() > 0)
|
|
||||||
{
|
|
||||||
glDrawElements(GL_TRIANGLES, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT, TIBuffer);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumLines() > 0)
|
|
||||||
{
|
|
||||||
glDrawElements(GL_LINES, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT, LIBuffer);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
if (IndexGenerator::GetNumPoints() > 0)
|
|
||||||
{
|
|
||||||
glDrawElements(GL_POINTS, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT, PIBuffer);
|
|
||||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphapass)
|
|
||||||
{
|
|
||||||
// restore color mask
|
|
||||||
g_renderer->SetColorMask();
|
|
||||||
|
|
||||||
if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract)
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +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 _OGL_VERTEXMANAGER_H_
|
|
||||||
#define _OGL_VERTEXMANAGER_H_
|
|
||||||
|
|
||||||
#include "CPMemory.h"
|
|
||||||
#include "NativeVertexWriter.h"
|
|
||||||
|
|
||||||
#include "../VertexManager.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// Handles the OpenGL details of drawing lots of vertices quickly.
|
|
||||||
// Other functionality is moving out.
|
|
||||||
class VertexManager : public ::VertexManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VertexManager();
|
|
||||||
~VertexManager();
|
|
||||||
|
|
||||||
void Draw(u32 stride, bool alphapass);
|
|
||||||
|
|
||||||
NativeVertexFormat* CreateNativeVertexFormat();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _VERTEXMANAGER_H_
|
|
|
@ -1,255 +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>
|
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "Profiler.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "VertexLoader.h"
|
|
||||||
#include "XFMemory.h"
|
|
||||||
#include "ImageWrite.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_VertexShaderCache.h"
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
#include "OGL_VertexManager.h"
|
|
||||||
|
|
||||||
#include "../Main.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
|
||||||
bool VertexShaderCache::s_displayCompileAlert;
|
|
||||||
GLuint VertexShaderCache::CurrentShader;
|
|
||||||
bool VertexShaderCache::ShaderEnabled;
|
|
||||||
|
|
||||||
static VERTEXSHADER *pShaderLast = NULL;
|
|
||||||
static int s_nMaxVertexInstructions;
|
|
||||||
|
|
||||||
void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
float f[4] = { f1, f2, f3, f4 };
|
|
||||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f)
|
|
||||||
{
|
|
||||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; i++,f+=4)
|
|
||||||
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VertexShaderCache::VertexShaderCache()
|
|
||||||
{
|
|
||||||
glEnable(GL_VERTEX_PROGRAM_ARB);
|
|
||||||
ShaderEnabled = true;
|
|
||||||
CurrentShader = 0;
|
|
||||||
memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid));
|
|
||||||
|
|
||||||
s_displayCompileAlert = true;
|
|
||||||
|
|
||||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
|
|
||||||
#if CG_VERSION_NUM == 2100
|
|
||||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
|
|
||||||
{
|
|
||||||
s_nMaxVertexInstructions = 4096;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexShaderCache::~VertexShaderCache()
|
|
||||||
{
|
|
||||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++)
|
|
||||||
iter->second.Destroy();
|
|
||||||
vshaders.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VertexShaderCache::SetShader(u32 components)
|
|
||||||
{
|
|
||||||
const VERTEXSHADER* const vs = GetShader(components);
|
|
||||||
if (vs)
|
|
||||||
{
|
|
||||||
SetCurrentShader(vs->glprogid);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VERTEXSHADER* VertexShaderCache::GetShader(u32 components)
|
|
||||||
{
|
|
||||||
DVSTARTPROFILE();
|
|
||||||
VERTEXSHADERUID uid;
|
|
||||||
GetVertexShaderId(&uid, components);
|
|
||||||
|
|
||||||
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
|
|
||||||
{
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID));
|
|
||||||
|
|
||||||
VSCache::iterator iter = vshaders.find(uid);
|
|
||||||
|
|
||||||
if (iter != vshaders.end()) {
|
|
||||||
iter->second.frameCount = frameCount;
|
|
||||||
VSCacheEntry &entry = iter->second;
|
|
||||||
if (&entry.shader != pShaderLast) {
|
|
||||||
pShaderLast = &entry.shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Make an entry in the table
|
|
||||||
VSCacheEntry& entry = vshaders[uid];
|
|
||||||
entry.frameCount = frameCount;
|
|
||||||
pShaderLast = &entry.shader;
|
|
||||||
const char *code = GenerateVertexShaderCode(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), counter++);
|
|
||||||
|
|
||||||
SaveData(szTemp, code);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) {
|
|
||||||
ERROR_LOG(VIDEO, "failed to create vertex shader");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
INCSTAT(stats.numVertexShadersCreated);
|
|
||||||
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
|
|
||||||
return pShaderLast;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
if (s_displayCompileAlert) {
|
|
||||||
PanicAlert("Failed to create vertex shader");
|
|
||||||
s_displayCompileAlert = false;
|
|
||||||
}
|
|
||||||
cgDestroyProgram(tempprog);
|
|
||||||
ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
|
||||||
ERROR_LOG(VIDEO, pstrprogram);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cgGetError() != CG_NO_ERROR)
|
|
||||||
{
|
|
||||||
WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
|
|
||||||
WARN_LOG(VIDEO, 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, pstrprogram);
|
|
||||||
ERROR_LOG(VIDEO, pcompiledprog);
|
|
||||||
}
|
|
||||||
|
|
||||||
cgDestroyProgram(tempprog);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
vs.strprog = pstrprogram;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,89 +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 _OGL_VERTEXSHADERCACHE_H_
|
|
||||||
#define _OGL_VERTEXSHADERCACHE_H_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "VertexShaderGen.h"
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
#include "../VertexShaderCache.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
struct VERTEXSHADER
|
|
||||||
{
|
|
||||||
VERTEXSHADER() : glprogid(0) {}
|
|
||||||
GLuint glprogid; // opengl program id
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
std::string strprog;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class VertexShaderCache : public ::VertexShaderCacheBase
|
|
||||||
{
|
|
||||||
struct VSCacheEntry
|
|
||||||
{
|
|
||||||
VERTEXSHADER shader;
|
|
||||||
int frameCount;
|
|
||||||
VSCacheEntry() : frameCount(0) {}
|
|
||||||
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 bool s_displayCompileAlert;
|
|
||||||
|
|
||||||
static GLuint CurrentShader;
|
|
||||||
static bool ShaderEnabled;
|
|
||||||
|
|
||||||
public:
|
|
||||||
VertexShaderCache();
|
|
||||||
~VertexShaderCache();
|
|
||||||
|
|
||||||
bool SetShader(u32 components);
|
|
||||||
|
|
||||||
static VERTEXSHADER* GetShader(u32 components);
|
|
||||||
static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
|
|
||||||
|
|
||||||
static void SetCurrentShader(GLuint Shader);
|
|
||||||
static void DisableShader();
|
|
||||||
|
|
||||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
|
||||||
void SetVSConstant4fv(unsigned int const_number, const float* f);
|
|
||||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f);
|
|
||||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _VERTEXSHADERCACHE_H_
|
|
|
@ -1,42 +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/
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------------------------
|
|
||||||
// This file handles the External Frame Buffer (XFB). The XFB is a storage point when the picture is resized
|
|
||||||
// by the system to the correct display format for output to the TV. In most cases its function can be
|
|
||||||
// supplemented by the equivalent adjustments in glScissor and glViewport (or their DirectX equivalents). But
|
|
||||||
// for some homebrew games these functions are necessary because the homebrew game communicate directly with
|
|
||||||
// them.
|
|
||||||
// ----------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// OGL
|
|
||||||
#include "OGL_Render.h"
|
|
||||||
#include "OGL_TextureConverter.h"
|
|
||||||
#include "OGL_FramebufferManager.h"
|
|
||||||
#include "OGL_XFB.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
|
||||||
{
|
|
||||||
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc);
|
|
||||||
TextureConverter::EncodeToRamYUYV(FramebufferManager::ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, dstWd, dstHt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +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 _OGL_XFB_H_
|
|
||||||
#define _OGL_XFB_H_
|
|
||||||
|
|
||||||
#include "OGL_GLUtil.h"
|
|
||||||
|
|
||||||
namespace OGL
|
|
||||||
{
|
|
||||||
|
|
||||||
// write the EFB to the XFB
|
|
||||||
void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _XFB_H_
|
|
|
@ -1,20 +0,0 @@
|
||||||
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
#include "PixelShaderCache.h"
|
|
||||||
|
|
||||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
g_pixel_shader_cache->SetPSConstant4f(const_number, f1, f2, f3, f4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPSConstant4fv(unsigned int const_number, const float *f)
|
|
||||||
{
|
|
||||||
g_pixel_shader_cache->SetPSConstant4fv(const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
|
||||||
{
|
|
||||||
g_pixel_shader_cache->SetMultiPSConstant4fv(const_number, count, f);
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
|
|
||||||
#ifndef _PIXELSHADERCACHE_H_
|
|
||||||
#define _PIXELSHADERCACHE_H_
|
|
||||||
|
|
||||||
class PixelShaderCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~PixelShaderCacheBase() {}
|
|
||||||
|
|
||||||
virtual bool SetShader(bool dstAlphaEnable) = 0;
|
|
||||||
|
|
||||||
virtual void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0;
|
|
||||||
virtual void SetPSConstant4fv(unsigned int const_number, const float *f) = 0;
|
|
||||||
virtual void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,390 +0,0 @@
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Timer.h"
|
|
||||||
|
|
||||||
#include "Render.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
#include "Atomic.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "FramebufferManager.h"
|
|
||||||
|
|
||||||
#include "Fifo.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "DLCache.h"
|
|
||||||
#include "OnScreenDisplay.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
|
|
||||||
#include "Renderer.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
int RendererBase::s_target_width;
|
|
||||||
int RendererBase::s_target_height;
|
|
||||||
|
|
||||||
int RendererBase::s_Fulltarget_width;
|
|
||||||
int RendererBase::s_Fulltarget_height;
|
|
||||||
|
|
||||||
int RendererBase::s_backbuffer_width;
|
|
||||||
int RendererBase::s_backbuffer_height;
|
|
||||||
|
|
||||||
int RendererBase::s_XFB_width;
|
|
||||||
int RendererBase::s_XFB_height;
|
|
||||||
|
|
||||||
float RendererBase::xScale;
|
|
||||||
float RendererBase::yScale;
|
|
||||||
|
|
||||||
int RendererBase::s_fps;
|
|
||||||
|
|
||||||
u32 RendererBase::s_blendMode;
|
|
||||||
bool RendererBase::XFBWrited;
|
|
||||||
|
|
||||||
float RendererBase::EFBxScale;
|
|
||||||
float RendererBase::EFByScale;
|
|
||||||
|
|
||||||
volatile u32 RendererBase::s_swapRequested;
|
|
||||||
|
|
||||||
//void VideoConfig::UpdateProjectionHack()
|
|
||||||
//{
|
|
||||||
// return;
|
|
||||||
// //::UpdateProjectionHack(g_Config.iPhackvalue);
|
|
||||||
//}
|
|
||||||
|
|
||||||
RendererBase::RendererBase()
|
|
||||||
{
|
|
||||||
UpdateActiveConfig();
|
|
||||||
s_blendMode = 0;
|
|
||||||
|
|
||||||
s_XFB_width = MAX_XFB_WIDTH;
|
|
||||||
s_XFB_height = MAX_XFB_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// can maybe reuse this func in Renderer::Swap to eliminate redundant code
|
|
||||||
void RendererBase::FramebufferSize(int w, int h)
|
|
||||||
{
|
|
||||||
TargetRectangle dst_rect;
|
|
||||||
ComputeDrawRectangle(w, h, false, &dst_rect);
|
|
||||||
|
|
||||||
xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width;
|
|
||||||
yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height;
|
|
||||||
|
|
||||||
// TODO: why these, prolly can remove them
|
|
||||||
const int s_LastAA = g_ActiveConfig.iMultisampleMode;
|
|
||||||
const int s_LastEFBScale = g_ActiveConfig.iEFBScale;
|
|
||||||
|
|
||||||
switch (s_LastEFBScale)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
EFBxScale = xScale;
|
|
||||||
EFByScale = yScale;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
EFBxScale = ceilf(xScale);
|
|
||||||
EFByScale = ceilf(yScale);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
EFByScale = EFBxScale = (g_ActiveConfig.iEFBScale - 1);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
const float SupersampleCoeficient = s_LastAA + 1;
|
|
||||||
EFBxScale *= SupersampleCoeficient;
|
|
||||||
EFByScale *= SupersampleCoeficient;
|
|
||||||
|
|
||||||
s_target_width = (int)(EFB_WIDTH * EFBxScale);
|
|
||||||
s_target_height = (int)(EFB_HEIGHT * EFByScale);
|
|
||||||
|
|
||||||
// TODO: set anything else?
|
|
||||||
s_Fulltarget_width = s_target_width;
|
|
||||||
s_Fulltarget_height = s_target_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateViewport()
|
|
||||||
{
|
|
||||||
g_renderer->UpdateViewport();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
RendererBase::RenderToXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// whats this for?
|
|
||||||
bool IsD3D()
|
|
||||||
{
|
|
||||||
//PanicAlert("IsD3D!");
|
|
||||||
// TODO: temporary
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::RenderText(const char *pstr, int left, int top, u32 color)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void RendererBase::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
|
|
||||||
{
|
|
||||||
if (!fbWidth || !fbHeight)
|
|
||||||
return;
|
|
||||||
|
|
||||||
VideoFifo_CheckEFBAccess();
|
|
||||||
VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight);
|
|
||||||
XFBWrited = true;
|
|
||||||
|
|
||||||
// XXX: Without the VI, how would we know what kind of field this is? So
|
|
||||||
// just use progressive.
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bUseXFB)
|
|
||||||
{
|
|
||||||
g_framebuffer_manager->CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight, sourceRc);
|
|
||||||
Common::AtomicStoreRelease(s_swapRequested, FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TargetRectangle RendererBase::ConvertEFBRectangle(const EFBRectangle& rc)
|
|
||||||
{
|
|
||||||
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
TargetRectangle result;
|
|
||||||
result.left = (int)(rc.left * EFBxScale) + Xstride;
|
|
||||||
result.top = (int)(rc.top * EFByScale) + Ystride;
|
|
||||||
result.right = (int)(rc.right * EFBxScale) + Xstride;
|
|
||||||
result.bottom = (int)(rc.bottom * EFByScale) + Ystride;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RendererBase::SetScissorRect(EFBRectangle &rc)
|
|
||||||
{
|
|
||||||
int xoff = bpmem.scissorOffset.x * 2 - 342;
|
|
||||||
int yoff = bpmem.scissorOffset.y * 2 - 342;
|
|
||||||
|
|
||||||
rc.left = bpmem.scissorTL.x - xoff - 342;
|
|
||||||
rc.top = bpmem.scissorTL.y - yoff - 342;
|
|
||||||
rc.right = bpmem.scissorBR.x - xoff - 341;
|
|
||||||
rc.bottom = bpmem.scissorBR.y - yoff - 341;
|
|
||||||
|
|
||||||
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
|
||||||
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
|
||||||
|
|
||||||
rc.left = (int)(rc.left * EFBxScale);
|
|
||||||
rc.top = (int)(rc.top * EFByScale);
|
|
||||||
rc.right = (int)(rc.right * EFBxScale);
|
|
||||||
rc.bottom = (int)(rc.bottom * EFByScale);
|
|
||||||
|
|
||||||
if (rc.left < 0) rc.left = 0;
|
|
||||||
if (rc.right < 0) rc.right = 0;
|
|
||||||
if (rc.left > s_target_width) rc.left = s_target_width;
|
|
||||||
if (rc.right > s_target_width) rc.right = s_target_width;
|
|
||||||
if (rc.top < 0) rc.top = 0;
|
|
||||||
if (rc.bottom < 0) rc.bottom = 0;
|
|
||||||
if (rc.top > s_target_height) rc.top = s_target_height;
|
|
||||||
if (rc.bottom > s_target_height) rc.bottom = s_target_height;
|
|
||||||
|
|
||||||
rc.left += Xstride;
|
|
||||||
rc.top += Ystride;
|
|
||||||
rc.right += Xstride;
|
|
||||||
rc.bottom += Ystride;
|
|
||||||
|
|
||||||
if (rc.left > rc.right)
|
|
||||||
{
|
|
||||||
int temp = rc.right;
|
|
||||||
rc.right = rc.left;
|
|
||||||
rc.left = temp;
|
|
||||||
}
|
|
||||||
if (rc.top > rc.bottom)
|
|
||||||
{
|
|
||||||
int temp = rc.bottom;
|
|
||||||
rc.bottom = rc.top;
|
|
||||||
rc.top = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (rc.right >= rc.left && rc.bottom >= rc.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RendererBase::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc)
|
|
||||||
{
|
|
||||||
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.bUseRealXFB) || !fbWidth || !fbHeight)
|
|
||||||
{
|
|
||||||
g_VideoInitialize.pCopiedToXFB(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function is called after the XFB field is changed, not after
|
|
||||||
// EFB is copied to XFB. In this way, flickering is reduced in games
|
|
||||||
// and seems to also give more FPS in ZTP
|
|
||||||
|
|
||||||
if (field == FIELD_LOWER)
|
|
||||||
xfbAddr -= fbWidth * 2;
|
|
||||||
u32 xfbCount = 0;
|
|
||||||
const XFBSourceBase** xfbSourceList = g_framebuffer_manager->GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
|
||||||
|
|
||||||
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
|
|
||||||
{
|
|
||||||
g_VideoInitialize.pCopiedToXFB(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_renderer->ResetAPIState();
|
|
||||||
|
|
||||||
// prepare copying the XFBs to our backbuffer
|
|
||||||
TargetRectangle dst_rect;
|
|
||||||
ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect);
|
|
||||||
|
|
||||||
g_renderer->PrepareXFBCopy(dst_rect);
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bUseXFB)
|
|
||||||
{
|
|
||||||
const XFBSourceBase* xfbSource;
|
|
||||||
|
|
||||||
// draw each xfb source
|
|
||||||
for (u32 i = 0; i < xfbCount; ++i)
|
|
||||||
{
|
|
||||||
xfbSource = xfbSourceList[i];
|
|
||||||
TargetRectangle sourceRc;
|
|
||||||
|
|
||||||
//if (g_ActiveConfig.bAutoScale)
|
|
||||||
//{
|
|
||||||
// sourceRc = xfbSource->sourceRc;
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
sourceRc.left = 0;
|
|
||||||
sourceRc.top = 0;
|
|
||||||
sourceRc.right = xfbSource->texWidth;
|
|
||||||
sourceRc.bottom = xfbSource->texHeight;
|
|
||||||
//}
|
|
||||||
|
|
||||||
MathUtil::Rectangle<float> drawRc;
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
|
|
||||||
{
|
|
||||||
// use virtual xfb with offset
|
|
||||||
int xfbHeight = xfbSource->srcHeight;
|
|
||||||
int xfbWidth = xfbSource->srcWidth;
|
|
||||||
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
|
|
||||||
|
|
||||||
drawRc.bottom = 1.0f - 2.0f * ((hOffset) / (float)fbHeight);
|
|
||||||
drawRc.top = 1.0f - 2.0f * ((hOffset + xfbHeight) / (float)fbHeight);
|
|
||||||
drawRc.left = -(xfbWidth / (float)fbWidth);
|
|
||||||
drawRc.right = (xfbWidth / (float)fbWidth);
|
|
||||||
|
|
||||||
if (!g_ActiveConfig.bAutoScale)
|
|
||||||
{
|
|
||||||
// scale draw area for a 1 to 1 pixel mapping with the draw target
|
|
||||||
float vScale = (float)fbHeight / (float)s_backbuffer_height;
|
|
||||||
float hScale = (float)fbWidth / (float)s_backbuffer_width;
|
|
||||||
|
|
||||||
drawRc.top *= vScale;
|
|
||||||
drawRc.bottom *= vScale;
|
|
||||||
drawRc.left *= hScale;
|
|
||||||
drawRc.right *= hScale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
drawRc.top = -1;
|
|
||||||
drawRc.bottom = 1;
|
|
||||||
drawRc.left = -1;
|
|
||||||
drawRc.right = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_renderer->Draw(xfbSource, sourceRc, drawRc, rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: organize drawRc stuff
|
|
||||||
MathUtil::Rectangle<float> drawRc;
|
|
||||||
drawRc.top = -1;
|
|
||||||
drawRc.bottom = 1;
|
|
||||||
drawRc.left = -1;
|
|
||||||
drawRc.right = 1;
|
|
||||||
|
|
||||||
const TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
|
||||||
g_renderer->Draw(NULL, targetRc, drawRc, rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with drawing the game stuff, good moment to save a screenshot
|
|
||||||
// TODO: screenshot code
|
|
||||||
//
|
|
||||||
|
|
||||||
// finally present some information
|
|
||||||
// TODO: debug text, fps, etc...
|
|
||||||
//
|
|
||||||
|
|
||||||
OSD::DrawMessages();
|
|
||||||
|
|
||||||
g_renderer->EndFrame();
|
|
||||||
|
|
||||||
++frameCount;
|
|
||||||
|
|
||||||
DLCache::ProgressiveCleanup();
|
|
||||||
g_texture_cache->Cleanup();
|
|
||||||
|
|
||||||
// check for configuration changes
|
|
||||||
const int last_efbscale = g_ActiveConfig.iEFBScale;
|
|
||||||
//const int last_aa = g_ActiveConfig.iMultisampleMode;
|
|
||||||
|
|
||||||
UpdateActiveConfig();
|
|
||||||
|
|
||||||
|
|
||||||
bool window_resized = g_renderer->CheckForResize();
|
|
||||||
|
|
||||||
bool xfbchanged = false;
|
|
||||||
if (s_XFB_width != fbWidth || s_XFB_height != fbHeight)
|
|
||||||
{
|
|
||||||
xfbchanged = true;
|
|
||||||
s_XFB_width = fbWidth;
|
|
||||||
s_XFB_height = fbHeight;
|
|
||||||
if (s_XFB_width < 1) s_XFB_width = MAX_XFB_WIDTH;
|
|
||||||
if (s_XFB_width > MAX_XFB_WIDTH) s_XFB_width = MAX_XFB_WIDTH;
|
|
||||||
if (s_XFB_height < 1) s_XFB_height = MAX_XFB_HEIGHT;
|
|
||||||
if (s_XFB_height > MAX_XFB_HEIGHT) s_XFB_height = MAX_XFB_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update FPS counter
|
|
||||||
// TODO: make this better
|
|
||||||
static int fpscount = 0;
|
|
||||||
static unsigned long lasttime = 0;
|
|
||||||
if (Common::Timer::GetTimeMs() - lasttime >= 1000)
|
|
||||||
{
|
|
||||||
lasttime = Common::Timer::GetTimeMs();
|
|
||||||
s_fps = fpscount;
|
|
||||||
fpscount = 0;
|
|
||||||
}
|
|
||||||
if (XFBWrited)
|
|
||||||
++fpscount;
|
|
||||||
|
|
||||||
// set default viewport and scissor, for the clear to work correctly
|
|
||||||
stats.ResetFrame();
|
|
||||||
|
|
||||||
// done. Show our work ;)
|
|
||||||
g_renderer->Present();
|
|
||||||
|
|
||||||
// resize the back buffers NOW to avoid flickering when resizing windows
|
|
||||||
if (xfbchanged || window_resized || last_efbscale != g_ActiveConfig.iEFBScale)
|
|
||||||
{
|
|
||||||
g_renderer->GetBackBufferSize(&s_backbuffer_width, &s_backbuffer_height);
|
|
||||||
|
|
||||||
FramebufferSize(s_backbuffer_width, s_backbuffer_height);
|
|
||||||
|
|
||||||
g_renderer->RecreateFramebufferManger();
|
|
||||||
}
|
|
||||||
|
|
||||||
// begin next frame
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
|
|
||||||
g_renderer->BeginFrame();
|
|
||||||
|
|
||||||
g_renderer->UpdateViewport();
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
g_VideoInitialize.pCopiedToXFB(XFBWrited || g_ActiveConfig.bUseRealXFB);
|
|
||||||
XFBWrited = false;
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
|
|
||||||
#ifndef _RENDER_H_
|
|
||||||
#define _RENDER_H_
|
|
||||||
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "CommonTypes.h"
|
|
||||||
#include "FramebufferManager.h"
|
|
||||||
|
|
||||||
class RendererBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RendererBase();
|
|
||||||
virtual ~RendererBase() {}
|
|
||||||
|
|
||||||
static void FramebufferSize(int w, int h);
|
|
||||||
|
|
||||||
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
|
|
||||||
|
|
||||||
virtual u32 AccessEFB(EFBAccessType type, int x, int y) = 0;
|
|
||||||
|
|
||||||
static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc);
|
|
||||||
|
|
||||||
// virtual funcs used in Swap()
|
|
||||||
virtual void PrepareXFBCopy(const TargetRectangle &dst_rect) = 0;
|
|
||||||
virtual void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
|
||||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc) = 0;
|
|
||||||
virtual void EndFrame() = 0;
|
|
||||||
virtual void Present() = 0;
|
|
||||||
virtual bool CheckForResize() = 0;
|
|
||||||
virtual void GetBackBufferSize(int* w, int* h) = 0;
|
|
||||||
virtual void RecreateFramebufferManger() = 0;
|
|
||||||
virtual void BeginFrame() = 0;
|
|
||||||
|
|
||||||
// hmm
|
|
||||||
virtual bool SetScissorRect() = 0;
|
|
||||||
static bool SetScissorRect(EFBRectangle &rc);
|
|
||||||
|
|
||||||
static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc);
|
|
||||||
|
|
||||||
virtual void UpdateViewport() = 0;
|
|
||||||
virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0;
|
|
||||||
|
|
||||||
virtual void ResetAPIState() = 0;
|
|
||||||
virtual void RestoreAPIState() = 0;
|
|
||||||
|
|
||||||
static int GetTargetWidth() { return s_target_width; }
|
|
||||||
static int GetTargetHeight() { return s_target_height; }
|
|
||||||
static int GetFullTargetWidth() { return s_Fulltarget_width; }
|
|
||||||
static int GetFullTargetHeight() { return s_Fulltarget_height; }
|
|
||||||
static float GetTargetScaleX() { return EFBxScale; }
|
|
||||||
static float GetTargetScaleY() { return EFByScale; }
|
|
||||||
static int GetFrameBufferWidth() { return s_backbuffer_width; }
|
|
||||||
static int GetFrameBufferHeight() { return s_backbuffer_height; }
|
|
||||||
static float GetXFBScaleX() { return xScale; }
|
|
||||||
static float GetXFBScaleY() { return yScale; }
|
|
||||||
|
|
||||||
virtual void SetColorMask() {}
|
|
||||||
virtual void SetBlendMode(bool forceUpdate) {}
|
|
||||||
virtual void SetSamplerState(int stage, int texindex) {}
|
|
||||||
virtual void SetDitherMode() {}
|
|
||||||
virtual void SetLineWidth() {}
|
|
||||||
virtual void SetInterlacingMode() {}
|
|
||||||
virtual void SetGenerationMode() = 0;
|
|
||||||
virtual void SetDepthMode() = 0;
|
|
||||||
virtual void SetLogicOpMode() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// TODO: are all of these needed?
|
|
||||||
static int s_target_width;
|
|
||||||
static int s_target_height;
|
|
||||||
|
|
||||||
static int s_Fulltarget_width;
|
|
||||||
static int s_Fulltarget_height;
|
|
||||||
|
|
||||||
static int s_backbuffer_width;
|
|
||||||
static int s_backbuffer_height;
|
|
||||||
//
|
|
||||||
|
|
||||||
static int s_fps;
|
|
||||||
|
|
||||||
static u32 s_blendMode;
|
|
||||||
static bool XFBWrited;
|
|
||||||
|
|
||||||
// these go with the settings in the GUI 1x,2x,3x,etc
|
|
||||||
static float EFBxScale;
|
|
||||||
static float EFByScale;
|
|
||||||
// these seem be the fractional value
|
|
||||||
// TODO: are these ones needed?
|
|
||||||
static float xScale;
|
|
||||||
static float yScale;
|
|
||||||
|
|
||||||
static int s_XFB_width;
|
|
||||||
static int s_XFB_height;
|
|
||||||
|
|
||||||
static volatile u32 s_swapRequested;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,64 +0,0 @@
|
||||||
# -*- python -*-
|
|
||||||
|
|
||||||
Import('env')
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
name = os.sep + "Plugin_VideoMerge"
|
|
||||||
|
|
||||||
files = [
|
|
||||||
'BPFunctions.cpp',
|
|
||||||
'FramebufferManager.cpp',
|
|
||||||
'Main.cpp',
|
|
||||||
'PixelShaderCache.cpp',
|
|
||||||
'Renderer.cpp',
|
|
||||||
'TextureCache.cpp',
|
|
||||||
'VertexManager.cpp',
|
|
||||||
'VertexShaderCache.cpp',
|
|
||||||
'VideoConfigDiag.cpp',
|
|
||||||
'OGL/OGL_FramebufferManager.cpp',
|
|
||||||
'OGL/OGL_GLUtil.cpp',
|
|
||||||
'OGL/OGL_NativeVertexFormat.cpp',
|
|
||||||
'OGL/OGL_PixelShaderCache.cpp',
|
|
||||||
'OGL/OGL_PostProcessing.cpp',
|
|
||||||
'OGL/OGL_RasterFont.cpp',
|
|
||||||
'OGL/OGL_Render.cpp',
|
|
||||||
'OGL/OGL_TextureCache.cpp',
|
|
||||||
'OGL/OGL_TextureConverter.cpp',
|
|
||||||
'OGL/OGL_VertexManager.cpp',
|
|
||||||
'OGL/OGL_VertexShaderCache.cpp',
|
|
||||||
'OGL/OGL_XFB.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
if sys.platform == 'win32': files += [
|
|
||||||
'EmuWindow.cpp',
|
|
||||||
'DX11/DX11_D3DBase.cpp',
|
|
||||||
'DX11/DX11_D3DBlob.cpp',
|
|
||||||
'DX11/DX11_D3DShader.cpp',
|
|
||||||
'DX11/DX11_D3DTexture.cpp',
|
|
||||||
'DX11/DX11_D3DUtil.cpp',
|
|
||||||
'DX11/DX11_FramebufferManager.cpp',
|
|
||||||
'DX11/DX11_GfxState.cpp',
|
|
||||||
'DX11/DX11_NativeVertexFormat.cpp',
|
|
||||||
'DX11/DX11_PixelShaderCache.cpp',
|
|
||||||
'DX11/DX11_Render.cpp',
|
|
||||||
'DX11/DX11_TextureCache.cpp',
|
|
||||||
'DX11/DX11_VertexManager.cpp',
|
|
||||||
'DX11/DX11_VertexShaderCache.cpp',
|
|
||||||
'DX9/DX9_D3DBase.cpp',
|
|
||||||
'DX9/DX9_D3DShader.cpp',
|
|
||||||
'DX9/DX9_D3DTexture.cpp',
|
|
||||||
'DX9/DX9_D3DUtil.cpp',
|
|
||||||
'DX9/DX9_FramebufferManager.cpp',
|
|
||||||
'DX9/DX9_NativeVertexFormat.cpp',
|
|
||||||
'DX9/DX9_PixelShaderCache.cpp',
|
|
||||||
'DX9/DX9_Render.cpp',
|
|
||||||
'DX9/DX9_TextureCache.cpp',
|
|
||||||
'DX9/DX9_TextureConverter.cpp',
|
|
||||||
'DX9/DX9_VertexManager.cpp',
|
|
||||||
'DX9/DX9_VertexShaderCache.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
libs = [ 'videocommon', 'GLEW', 'SOIL', 'common' ]
|
|
||||||
|
|
||||||
env.SharedLibrary(env['plugin_dir'] + name, files, LIBS = env['LIBS'] + libs)
|
|
|
@ -1,525 +0,0 @@
|
||||||
|
|
||||||
// Common
|
|
||||||
#include "MemoryUtil.h"
|
|
||||||
|
|
||||||
#include "TextureCache.h"
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "TextureDecoder.h"
|
|
||||||
#include "HiresTextures.h"
|
|
||||||
|
|
||||||
#include "Statistics.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
TextureCacheBase::TexCache TextureCacheBase::textures;
|
|
||||||
u8 *TextureCacheBase::temp;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TEMP_SIZE = (1024 * 1024 * 4),
|
|
||||||
TEXTURE_KILL_THRESHOLD = 200,
|
|
||||||
};
|
|
||||||
|
|
||||||
// returns the exponent of the smallest power of two which is greater than val
|
|
||||||
unsigned int GetPow2(unsigned int val)
|
|
||||||
{
|
|
||||||
unsigned int ret = 0;
|
|
||||||
for (; val; val >>= 1)
|
|
||||||
++ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCacheBase::TCacheEntryBase::~TCacheEntryBase()
|
|
||||||
{
|
|
||||||
// TODO: can we just use (addr) and remove the other checks?
|
|
||||||
// will need changes to TextureCache::Load and CopyRenderTargetToTexture
|
|
||||||
if (addr && false == (isRenderTarget || g_ActiveConfig.bSafeTextureCache))
|
|
||||||
{
|
|
||||||
u32* ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr);
|
|
||||||
if (ptr && *ptr == hash)
|
|
||||||
*ptr = oldpixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureCacheBase::TCacheEntryBase::IntersectsMemoryRange(u32 range_address, u32 range_size) const
|
|
||||||
{
|
|
||||||
if (addr + size_in_bytes < range_address)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (addr >= range_address + range_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCacheBase::TextureCacheBase()
|
|
||||||
{
|
|
||||||
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
|
||||||
TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter);
|
|
||||||
HiresTextures::Init(g_globals->unique_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::Cleanup()
|
|
||||||
{
|
|
||||||
TexCache::iterator
|
|
||||||
iter = textures.begin(),
|
|
||||||
tcend = textures.end();
|
|
||||||
while (iter != tcend)
|
|
||||||
{
|
|
||||||
if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
|
|
||||||
{
|
|
||||||
delete iter->second;
|
|
||||||
textures.erase(iter++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCacheBase::~TextureCacheBase()
|
|
||||||
{
|
|
||||||
Invalidate(true);
|
|
||||||
FreeMemoryPages(temp, TEMP_SIZE);
|
|
||||||
temp = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::ClearRenderTargets()
|
|
||||||
{
|
|
||||||
TexCache::iterator
|
|
||||||
iter = textures.begin(),
|
|
||||||
tcend = textures.end();
|
|
||||||
for (; iter!=tcend; ++iter)
|
|
||||||
iter->second->isRenderTarget = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::MakeRangeDynamic(u32 start_address, u32 size)
|
|
||||||
{
|
|
||||||
TexCache::iterator
|
|
||||||
iter = textures.begin(),
|
|
||||||
tcend = textures.end();
|
|
||||||
for (; iter!=tcend; ++iter)
|
|
||||||
{
|
|
||||||
// TODO: an int ??
|
|
||||||
int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
|
|
||||||
if (0 == rangePosition)
|
|
||||||
iter->second->hash = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::Invalidate(bool shutdown)
|
|
||||||
{
|
|
||||||
TexCache::iterator
|
|
||||||
iter = textures.begin(),
|
|
||||||
tcend = textures.end();
|
|
||||||
for (; iter!=tcend; ++iter)
|
|
||||||
{
|
|
||||||
// TODO: this could be better
|
|
||||||
if (shutdown)
|
|
||||||
iter->second->addr = 0; // hax, not even helpin
|
|
||||||
delete iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
textures.clear();
|
|
||||||
HiresTextures::Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::InvalidateRange(u32 start_address, u32 size)
|
|
||||||
{
|
|
||||||
TexCache::iterator
|
|
||||||
iter = textures.begin(),
|
|
||||||
tcend = textures.end();
|
|
||||||
while (iter != tcend)
|
|
||||||
{
|
|
||||||
if (iter->second->IntersectsMemoryRange(start_address, size))
|
|
||||||
{
|
|
||||||
delete iter->second;
|
|
||||||
textures.erase(iter++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(unsigned int stage,
|
|
||||||
u32 address, unsigned int width, unsigned int height, unsigned int tex_format,
|
|
||||||
unsigned int tlutaddr, unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel)
|
|
||||||
{
|
|
||||||
// necessary?
|
|
||||||
if (0 == address)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
u8* ptr = g_VideoInitialize.pGetMemoryPointer(address);
|
|
||||||
|
|
||||||
// TexelSizeInNibbles(format)*width*height/16;
|
|
||||||
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1;
|
|
||||||
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1;
|
|
||||||
|
|
||||||
unsigned int expandedWidth = (width + bsw) & (~bsw);
|
|
||||||
unsigned int expandedHeight = (height + bsh) & (~bsh);
|
|
||||||
|
|
||||||
u64 hash_value = 0;
|
|
||||||
u64 texHash = 0;
|
|
||||||
u32 texID = address;
|
|
||||||
u32 FullFormat = tex_format;
|
|
||||||
u32 size_in_bytes = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format);
|
|
||||||
|
|
||||||
switch (tex_format)
|
|
||||||
{
|
|
||||||
case GX_TF_C4:
|
|
||||||
case GX_TF_C8:
|
|
||||||
case GX_TF_C14X2:
|
|
||||||
FullFormat = tex_format | (tlutfmt << 16);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hires textures and texture dumping not supported, yet
|
|
||||||
if (g_ActiveConfig.bSafeTextureCache/* || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures*/)
|
|
||||||
{
|
|
||||||
texHash = GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
|
||||||
|
|
||||||
switch (tex_format)
|
|
||||||
{
|
|
||||||
case GX_TF_C4:
|
|
||||||
case GX_TF_C8:
|
|
||||||
case GX_TF_C14X2:
|
|
||||||
{
|
|
||||||
// WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up)
|
|
||||||
// tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower.
|
|
||||||
// This trick (to change the texID depending on the TLUT addr) is a trick to get around
|
|
||||||
// an issue with metroid prime's fonts, where it has multiple sets of fonts on top of
|
|
||||||
// each other stored in a single texture, and uses the palette to make different characters
|
|
||||||
// visible or invisible. Thus, unless we want to recreate the textures for every drawn character,
|
|
||||||
// we must make sure that texture with different tluts get different IDs.
|
|
||||||
const u64 tlutHash = GetHash64(texMem + tlutaddr, TexDecoder_GetPaletteSize(tex_format),
|
|
||||||
g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
|
||||||
|
|
||||||
texHash ^= tlutHash;
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bSafeTextureCache)
|
|
||||||
texID ^= ((u32)tlutHash) ^ (tlutHash >> 32);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bSafeTextureCache)
|
|
||||||
hash_value = texHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skip_texture_create = false;
|
|
||||||
|
|
||||||
TCacheEntryBase *entry = textures[texID];
|
|
||||||
if (entry)
|
|
||||||
{
|
|
||||||
if (!g_ActiveConfig.bSafeTextureCache)
|
|
||||||
hash_value = *(u32*)ptr;
|
|
||||||
|
|
||||||
// TODO: Is the (entry->MipLevels == maxlevel) check needed?
|
|
||||||
if (entry->isRenderTarget ||
|
|
||||||
(address == entry->addr && hash_value == entry->hash &&
|
|
||||||
FullFormat == entry->fmt && entry->MipLevels == maxlevel))
|
|
||||||
{
|
|
||||||
goto return_entry;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Let's reload the new texture data into the same texture,
|
|
||||||
// instead of destroying it and having to create a new one.
|
|
||||||
// Might speed up movie playback very, very slightly.
|
|
||||||
|
|
||||||
// TODO: Is the (entry->MipLevels < maxlevel) check needed?
|
|
||||||
if (width == entry->w && height==entry->h &&
|
|
||||||
FullFormat == entry->fmt && entry->MipLevels < maxlevel)
|
|
||||||
{
|
|
||||||
goto load_texture;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the texture
|
|
||||||
|
|
||||||
const bool isPow2 = !((width & (width - 1)) || (height & (height - 1)));
|
|
||||||
unsigned int TexLevels = (isPow2 && UseNativeMips && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2;
|
|
||||||
|
|
||||||
// TODO: what is ((maxlevel + 1) && maxlevel) ?
|
|
||||||
if (TexLevels > (maxlevel + 1) && maxlevel)
|
|
||||||
TexLevels = maxlevel + 1;
|
|
||||||
|
|
||||||
const PC_TexFormat pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth,
|
|
||||||
expandedHeight, tex_format, tlutaddr, tlutfmt, true);
|
|
||||||
|
|
||||||
textures[texID] = entry = CreateTexture(width, height, expandedWidth, TexLevels, pcfmt);
|
|
||||||
|
|
||||||
entry->oldpixel = *(u32*)ptr;
|
|
||||||
entry->addr = address;
|
|
||||||
entry->w = width;
|
|
||||||
entry->h = height;
|
|
||||||
entry->fmt = FullFormat;
|
|
||||||
entry->MipLevels = maxlevel;
|
|
||||||
entry->size_in_bytes = size_in_bytes;
|
|
||||||
|
|
||||||
entry->isRenderTarget = false;
|
|
||||||
entry->isNonPow2 = false;
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bSafeTextureCache)
|
|
||||||
entry->hash = hash_value;
|
|
||||||
else
|
|
||||||
// WTF is this rand() doing here?
|
|
||||||
entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF);
|
|
||||||
|
|
||||||
load_texture:
|
|
||||||
|
|
||||||
entry->Load(width, height, expandedWidth, 0);
|
|
||||||
|
|
||||||
if (TexLevels > 1 && pcfmt != PC_TEX_FMT_NONE)
|
|
||||||
{
|
|
||||||
const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format);
|
|
||||||
|
|
||||||
unsigned int level = 1;
|
|
||||||
unsigned int mipWidth = (width + 1) >> 1;
|
|
||||||
unsigned int mipHeight = (height + 1) >> 1;
|
|
||||||
ptr += entry->size_in_bytes;
|
|
||||||
|
|
||||||
while ((mipHeight || mipWidth) && (level < TexLevels))
|
|
||||||
{
|
|
||||||
const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1;
|
|
||||||
const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1;
|
|
||||||
|
|
||||||
expandedWidth = (currentWidth + bsw) & (~bsw);
|
|
||||||
expandedHeight = (currentHeight + bsh) & (~bsh);
|
|
||||||
|
|
||||||
TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true);
|
|
||||||
//entry->Load(currentWidth, currentHeight, expandedWidth, level);
|
|
||||||
|
|
||||||
ptr += ((max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1);
|
|
||||||
mipWidth >>= 1;
|
|
||||||
mipHeight >>= 1;
|
|
||||||
++level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INCSTAT(stats.numTexturesCreated);
|
|
||||||
SETSTAT(stats.numTexturesAlive, (int)textures.size());
|
|
||||||
|
|
||||||
return_entry:
|
|
||||||
|
|
||||||
entry->frameCount = frameCount;
|
|
||||||
entry->Bind(stage);
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextureCacheBase::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer,
|
|
||||||
bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect)
|
|
||||||
{
|
|
||||||
float colmat[20] = {};
|
|
||||||
// last four floats for fConstAdd
|
|
||||||
float *const fConstAdd = colmat + 16;
|
|
||||||
unsigned int cbufid = -1;
|
|
||||||
|
|
||||||
// TODO: Move this to TextureCache::Init()
|
|
||||||
if (bFromZBuffer)
|
|
||||||
{
|
|
||||||
switch (copyfmt)
|
|
||||||
{
|
|
||||||
case 0: // Z4
|
|
||||||
case 1: // Z8
|
|
||||||
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
|
|
||||||
cbufid = 12;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: // Z16 //?
|
|
||||||
colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
|
|
||||||
cbufid = 13;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 11: // Z16 (reverse order)
|
|
||||||
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
|
|
||||||
cbufid = 14;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6: // Z24X8
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = 1.0f;
|
|
||||||
cbufid = 15;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 9: // Z8M
|
|
||||||
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
|
|
||||||
cbufid = 16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 10: // Z8L
|
|
||||||
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
|
|
||||||
cbufid = 17;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 12: // Z16L
|
|
||||||
colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f;
|
|
||||||
cbufid = 18;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt);
|
|
||||||
colmat[2] = colmat[5] = colmat[8] = 1.0f;
|
|
||||||
cbufid = 19;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (bIsIntensityFmt)
|
|
||||||
{
|
|
||||||
fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f/255.0f;
|
|
||||||
switch (copyfmt)
|
|
||||||
{
|
|
||||||
case 0: // I4
|
|
||||||
case 1: // I8
|
|
||||||
case 2: // IA4
|
|
||||||
case 3: // IA8
|
|
||||||
// TODO - verify these coefficients
|
|
||||||
colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f;
|
|
||||||
colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f;
|
|
||||||
colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f;
|
|
||||||
|
|
||||||
if (copyfmt < 2)
|
|
||||||
{
|
|
||||||
fConstAdd[3] = 16.0f / 255.0f;
|
|
||||||
colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f;
|
|
||||||
cbufid = 0;
|
|
||||||
}
|
|
||||||
else// alpha
|
|
||||||
{
|
|
||||||
colmat[15] = 1;
|
|
||||||
cbufid = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt);
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (copyfmt)
|
|
||||||
{
|
|
||||||
case 0: // R4
|
|
||||||
case 8: // R8
|
|
||||||
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
|
|
||||||
cbufid = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // RA4
|
|
||||||
case 3: // RA8
|
|
||||||
colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1;
|
|
||||||
cbufid = 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: // A8
|
|
||||||
colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1;
|
|
||||||
cbufid = 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 9: // G8
|
|
||||||
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1;
|
|
||||||
cbufid = 5;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 10: // B8
|
|
||||||
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1;
|
|
||||||
cbufid = 6;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 11: // RG8
|
|
||||||
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1;
|
|
||||||
cbufid = 7;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 12: // GB8
|
|
||||||
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1;
|
|
||||||
cbufid = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: // RGB565
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = 1;
|
|
||||||
fConstAdd[3] = 1; // set alpha to 1
|
|
||||||
cbufid = 9;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5: // RGB5A3
|
|
||||||
case 6: // RGBA8
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
||||||
cbufid = 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt);
|
|
||||||
colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1;
|
|
||||||
cbufid = 11;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf);
|
|
||||||
const int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf);
|
|
||||||
|
|
||||||
const int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_w * g_renderer->GetTargetScaleX()) : tex_w;
|
|
||||||
const int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_h * g_renderer->GetTargetScaleY()) : tex_h;
|
|
||||||
|
|
||||||
TCacheEntryBase* entry = NULL;
|
|
||||||
|
|
||||||
const TexCache::iterator iter = textures.find(address);
|
|
||||||
if (textures.end() != iter)
|
|
||||||
{
|
|
||||||
entry = iter->second;
|
|
||||||
|
|
||||||
if (entry->isRenderTarget && entry->Scaledw == scaled_tex_w && entry->Scaledh == scaled_tex_h)
|
|
||||||
{
|
|
||||||
goto load_texture;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// remove it and recreate it as a render target
|
|
||||||
delete entry;
|
|
||||||
textures.erase(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the texture
|
|
||||||
textures[address] = entry = CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
|
|
||||||
|
|
||||||
if (NULL == entry)
|
|
||||||
PanicAlert("CopyRenderTargetToTexture failed to create entry.texture at %s %d\n", __FILE__, __LINE__);
|
|
||||||
|
|
||||||
entry->addr = 0; // TODO: probably can use this and eliminate isRenderTarget
|
|
||||||
entry->hash = 0;
|
|
||||||
entry->w = tex_w;
|
|
||||||
entry->h = tex_h;
|
|
||||||
entry->Scaledw = scaled_tex_w;
|
|
||||||
entry->Scaledh = scaled_tex_h;
|
|
||||||
entry->fmt = copyfmt;
|
|
||||||
|
|
||||||
entry->isRenderTarget = true;
|
|
||||||
entry->isNonPow2 = true; // TODO: is this used anywhere?
|
|
||||||
|
|
||||||
load_texture:
|
|
||||||
|
|
||||||
entry->frameCount = frameCount;
|
|
||||||
|
|
||||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
|
||||||
|
|
||||||
// load the texture
|
|
||||||
entry->FromRenderTarget(bFromZBuffer, bScaleByHalf, cbufid, colmat, source_rect);
|
|
||||||
|
|
||||||
g_renderer->RestoreAPIState();
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
|
|
||||||
#ifndef _TEXTURECACHE_H_
|
|
||||||
#define _TEXTURECACHE_H_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "CommonTypes.h"
|
|
||||||
#include "VideoCommon.h"
|
|
||||||
#include "TextureDecoder.h"
|
|
||||||
|
|
||||||
unsigned int GetPow2(unsigned int val);
|
|
||||||
|
|
||||||
class TextureCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct TCacheEntryBase
|
|
||||||
{
|
|
||||||
u32 addr;
|
|
||||||
u32 size_in_bytes;
|
|
||||||
u64 hash;
|
|
||||||
u32 paletteHash;
|
|
||||||
u32 oldpixel;
|
|
||||||
|
|
||||||
int frameCount;
|
|
||||||
unsigned int w, h, fmt, MipLevels;
|
|
||||||
int Scaledw, Scaledh;
|
|
||||||
|
|
||||||
bool isRenderTarget;
|
|
||||||
bool isNonPow2;
|
|
||||||
|
|
||||||
TCacheEntryBase() : addr(0), size_in_bytes(0), hash(0), paletteHash(0), oldpixel(0),
|
|
||||||
frameCount(0), w(0), h(0), fmt(0), MipLevels(0), Scaledw(0), Scaledh(0),
|
|
||||||
isRenderTarget(false), isNonPow2(true) {}
|
|
||||||
|
|
||||||
virtual ~TCacheEntryBase();
|
|
||||||
|
|
||||||
virtual void Load(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int levels) = 0;
|
|
||||||
|
|
||||||
virtual void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
|
|
||||||
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) = 0;
|
|
||||||
|
|
||||||
virtual void Bind(unsigned int stage) = 0;
|
|
||||||
|
|
||||||
bool IntersectsMemoryRange(u32 range_address, u32 range_size) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
friend struct TCacheEntryBase;
|
|
||||||
|
|
||||||
TextureCacheBase();
|
|
||||||
virtual ~TextureCacheBase();
|
|
||||||
|
|
||||||
static void Cleanup();
|
|
||||||
|
|
||||||
static void Invalidate(bool shutdown);
|
|
||||||
static void InvalidateRange(u32 start_address, u32 size);
|
|
||||||
|
|
||||||
// TODO: make these 2 static?
|
|
||||||
TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width,
|
|
||||||
unsigned int height, unsigned int tex_format, unsigned int tlutaddr,
|
|
||||||
unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel);
|
|
||||||
|
|
||||||
void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt,
|
|
||||||
u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect);
|
|
||||||
|
|
||||||
virtual TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
|
||||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0;
|
|
||||||
|
|
||||||
virtual TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) = 0;
|
|
||||||
|
|
||||||
static void ClearRenderTargets();
|
|
||||||
static void MakeRangeDynamic(u32 start_address, u32 size);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef std::map<u32, TCacheEntryBase*> TexCache;
|
|
||||||
static TexCache textures;
|
|
||||||
static u8 *temp;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,268 +0,0 @@
|
||||||
|
|
||||||
// VideoCommon
|
|
||||||
|
|
||||||
#include "CommonTypes.h"
|
|
||||||
|
|
||||||
#include "OpcodeDecoding.h"
|
|
||||||
#include "IndexGenerator.h"
|
|
||||||
#include "Statistics.h"
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "PixelShaderManager.h"
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "Profiler.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
#include "TextureCache.h"
|
|
||||||
#include "VertexManager.h"
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
u16* VertexManagerBase::TIBuffer;
|
|
||||||
u16* VertexManagerBase::LIBuffer;
|
|
||||||
u16* VertexManagerBase::PIBuffer;
|
|
||||||
bool VertexManagerBase::Flushed;
|
|
||||||
|
|
||||||
int VertexManagerBase::lastPrimitive;
|
|
||||||
u8* VertexManagerBase::LocalVBuffer;
|
|
||||||
|
|
||||||
// TODO: put this in .h perhaps
|
|
||||||
extern NativeVertexFormat* g_nativeVertexFmt;
|
|
||||||
|
|
||||||
NativeVertexFormat* NativeVertexFormat::Create()
|
|
||||||
{
|
|
||||||
return g_vertex_manager->CreateNativeVertexFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManagerBase::ResetBuffer()
|
|
||||||
{
|
|
||||||
s_pCurBufferPointer = LocalVBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexManagerBase::VertexManagerBase()
|
|
||||||
{
|
|
||||||
LocalVBuffer = new u8[MAXVBUFFERSIZE];
|
|
||||||
TIBuffer = new u16[MAXIBUFFERSIZE];
|
|
||||||
LIBuffer = new u16[MAXIBUFFERSIZE];
|
|
||||||
PIBuffer = new u16[MAXIBUFFERSIZE];
|
|
||||||
|
|
||||||
s_pCurBufferPointer = LocalVBuffer;
|
|
||||||
s_pBaseBufferPointer = LocalVBuffer;
|
|
||||||
|
|
||||||
Flushed = false;
|
|
||||||
|
|
||||||
IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexManagerBase::~VertexManagerBase()
|
|
||||||
{
|
|
||||||
delete[] LocalVBuffer;
|
|
||||||
delete[] TIBuffer;
|
|
||||||
delete[] LIBuffer;
|
|
||||||
delete[] PIBuffer;
|
|
||||||
|
|
||||||
// most likely not needed
|
|
||||||
ResetBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManagerBase::AddIndices(int _primitive, int _numVertices)
|
|
||||||
{
|
|
||||||
switch (_primitive)
|
|
||||||
{
|
|
||||||
case GX_DRAW_QUADS:
|
|
||||||
IndexGenerator::AddQuads(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_TRIANGLES:
|
|
||||||
IndexGenerator::AddList(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_TRIANGLE_STRIP:
|
|
||||||
IndexGenerator::AddStrip(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_TRIANGLE_FAN:
|
|
||||||
IndexGenerator::AddFan(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_LINE_STRIP:
|
|
||||||
IndexGenerator::AddLineStrip(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_LINES:
|
|
||||||
IndexGenerator::AddLineList(_numVertices);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_POINTS:
|
|
||||||
IndexGenerator::AddPoints(_numVertices);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int VertexManager::GetRemainingSize()
|
|
||||||
{
|
|
||||||
return VertexManagerBase::GetRemainingSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
int VertexManagerBase::GetRemainingSize()
|
|
||||||
{
|
|
||||||
return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int VertexManagerBase::GetRemainingVertices(int primitive)
|
|
||||||
{
|
|
||||||
switch (primitive)
|
|
||||||
{
|
|
||||||
case GX_DRAW_QUADS:
|
|
||||||
case GX_DRAW_TRIANGLES:
|
|
||||||
case GX_DRAW_TRIANGLE_STRIP:
|
|
||||||
case GX_DRAW_TRIANGLE_FAN:
|
|
||||||
return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_LINE_STRIP:
|
|
||||||
case GX_DRAW_LINES:
|
|
||||||
return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_POINTS:
|
|
||||||
return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManager::AddVertices(int _primitive, int _numVertices)
|
|
||||||
{
|
|
||||||
VertexManagerBase::AddVertices(_primitive, _numVertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManagerBase::AddVertices(int _primitive, int _numVertices)
|
|
||||||
{
|
|
||||||
if (_numVertices <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (_primitive)
|
|
||||||
{
|
|
||||||
case GX_DRAW_QUADS:
|
|
||||||
case GX_DRAW_TRIANGLES:
|
|
||||||
case GX_DRAW_TRIANGLE_STRIP:
|
|
||||||
case GX_DRAW_TRIANGLE_FAN:
|
|
||||||
if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * _numVertices)
|
|
||||||
g_vertex_manager->Flush();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_LINE_STRIP:
|
|
||||||
case GX_DRAW_LINES:
|
|
||||||
if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * _numVertices)
|
|
||||||
g_vertex_manager->Flush();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GX_DRAW_POINTS:
|
|
||||||
if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < _numVertices)
|
|
||||||
g_vertex_manager->Flush();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Flushed)
|
|
||||||
{
|
|
||||||
IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer);
|
|
||||||
Flushed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPrimitive = _primitive;
|
|
||||||
ADDSTAT(stats.thisFrame.numPrims, _numVertices);
|
|
||||||
INCSTAT(stats.thisFrame.numPrimitiveJoins);
|
|
||||||
AddIndices(_primitive, _numVertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManager::Flush()
|
|
||||||
{
|
|
||||||
VertexManagerBase::Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VertexManagerBase::Flush()
|
|
||||||
{
|
|
||||||
if (LocalVBuffer == s_pCurBufferPointer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Flushed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Flushed = true;
|
|
||||||
|
|
||||||
VideoFifo_CheckEFBAccess();
|
|
||||||
|
|
||||||
DVSTARTPROFILE();
|
|
||||||
|
|
||||||
u32 usedtextures = 0;
|
|
||||||
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
|
|
||||||
{
|
|
||||||
if (bpmem.tevorders[i/2].getEnable(i & 1))
|
|
||||||
usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bpmem.genMode.numindstages > 0)
|
|
||||||
for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1; ++i)
|
|
||||||
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
|
|
||||||
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 8; ++i)
|
|
||||||
{
|
|
||||||
if (usedtextures & (1 << i))
|
|
||||||
{
|
|
||||||
g_renderer->SetSamplerState(i & 3, i >> 2);
|
|
||||||
|
|
||||||
FourTexUnits &tex = bpmem.tex[i >> 2];
|
|
||||||
|
|
||||||
TextureCacheBase::TCacheEntryBase* tentry = g_texture_cache->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) && g_ActiveConfig.bUseNativeMips,
|
|
||||||
(tex.texMode1[i&3].max_lod >> 4));
|
|
||||||
|
|
||||||
if (tentry)
|
|
||||||
PixelShaderManager::SetTexDims(i, tentry->w, tentry->h, 0, 0);
|
|
||||||
else
|
|
||||||
ERROR_LOG(VIDEO, "error loading texture");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexShaderManager::SetConstants();
|
|
||||||
PixelShaderManager::SetConstants();
|
|
||||||
|
|
||||||
if (false == g_pixel_shader_cache->SetShader(false))
|
|
||||||
goto shader_fail;
|
|
||||||
|
|
||||||
if (false == g_vertex_shader_cache->SetShader(g_nativeVertexFmt->m_components))
|
|
||||||
goto shader_fail;
|
|
||||||
|
|
||||||
const unsigned int stride = g_nativeVertexFmt->GetVertexStride();
|
|
||||||
g_nativeVertexFmt->SetupVertexPointers();
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
g_vertex_manager->Draw(stride, false);
|
|
||||||
|
|
||||||
if (false == g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate)
|
|
||||||
{
|
|
||||||
if (false == g_pixel_shader_cache->SetShader(true))
|
|
||||||
goto shader_fail;
|
|
||||||
|
|
||||||
// update alpha only
|
|
||||||
g_vertex_manager->Draw(stride, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer);
|
|
||||||
|
|
||||||
shader_fail:
|
|
||||||
ResetBuffer();
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
|
|
||||||
#ifndef _VERTExMANAGER_H_
|
|
||||||
#define _VERTExMANAGER_H_
|
|
||||||
|
|
||||||
#include "NativeVertexFormat.h"
|
|
||||||
#include "NativeVertexWriter.h"
|
|
||||||
#include "BPMemory.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MAXVBUFFERSIZE = 0x50000,
|
|
||||||
MAXIBUFFERSIZE = 0x10000,
|
|
||||||
};
|
|
||||||
|
|
||||||
using VertexManager::s_pBaseBufferPointer;
|
|
||||||
using VertexManager::s_pCurBufferPointer;
|
|
||||||
|
|
||||||
extern NativeVertexFormat *g_nativeVertexFmt;
|
|
||||||
|
|
||||||
class VertexManagerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VertexManagerBase();
|
|
||||||
virtual ~VertexManagerBase();
|
|
||||||
|
|
||||||
static void Flush();
|
|
||||||
virtual void Draw(u32 stride, bool alphapass) = 0;
|
|
||||||
|
|
||||||
virtual NativeVertexFormat* CreateNativeVertexFormat() = 0;
|
|
||||||
|
|
||||||
static void AddIndices(int _primitive, int _numVertices);
|
|
||||||
static int GetRemainingSize();
|
|
||||||
static int GetRemainingVertices(int primitive);
|
|
||||||
static void AddVertices(int _primitive, int _numVertices);
|
|
||||||
static void ResetBuffer();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static u16* TIBuffer;
|
|
||||||
static u16* LIBuffer;
|
|
||||||
static u16* PIBuffer;
|
|
||||||
static bool Flushed;
|
|
||||||
|
|
||||||
static int lastPrimitive;
|
|
||||||
static u8* LocalVBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
|
|
||||||
#include "Main.h"
|
|
||||||
#include "VertexShaderCache.h"
|
|
||||||
|
|
||||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
|
||||||
{
|
|
||||||
g_vertex_shader_cache->SetVSConstant4f(const_number, f1, f2, f3, f4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVSConstant4fv(unsigned int const_number, const float* f)
|
|
||||||
{
|
|
||||||
g_vertex_shader_cache->SetVSConstant4fv(const_number, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f)
|
|
||||||
{
|
|
||||||
g_vertex_shader_cache->SetMultiVSConstant3fv(const_number, count, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
|
|
||||||
{
|
|
||||||
g_vertex_shader_cache->SetMultiVSConstant4fv(const_number, count, f);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
|
|
||||||
#ifndef _VERTEXSHADERCACHE_H_
|
|
||||||
#define _VERTEXSHADERCACHE_H_
|
|
||||||
|
|
||||||
class VertexShaderCacheBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~VertexShaderCacheBase() {}
|
|
||||||
|
|
||||||
virtual bool SetShader(u32 components) = 0;
|
|
||||||
|
|
||||||
virtual void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0;
|
|
||||||
virtual void SetVSConstant4fv(unsigned int const_number, const float* f) = 0;
|
|
||||||
virtual void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) = 0;
|
|
||||||
virtual void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,245 +0,0 @@
|
||||||
|
|
||||||
#include "VideoConfigDiag.h"
|
|
||||||
|
|
||||||
#include "VideoConfig.h"
|
|
||||||
#include "Main.h"
|
|
||||||
|
|
||||||
#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s)
|
|
||||||
|
|
||||||
// template instantiation
|
|
||||||
template class BoolSetting<wxCheckBox>;
|
|
||||||
template class BoolSetting<wxRadioButton>;
|
|
||||||
|
|
||||||
typedef BoolSetting<wxCheckBox> SettingCheckBox;
|
|
||||||
typedef BoolSetting<wxRadioButton> SettingRadioButton;
|
|
||||||
|
|
||||||
SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style)
|
|
||||||
: wxCheckBox(parent, -1, label, wxDefaultPosition, wxDefaultSize, style)
|
|
||||||
, m_setting(setting)
|
|
||||||
, m_reverse(reverse)
|
|
||||||
{
|
|
||||||
SetValue(m_setting ^ m_reverse);
|
|
||||||
_connect_macro_(this, BoolSetting<W>::UpdateValue, wxEVT_COMMAND_CHECKBOX_CLICKED, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style)
|
|
||||||
: wxRadioButton(parent, -1, label, wxDefaultPosition, wxDefaultSize, style)
|
|
||||||
, m_setting(setting)
|
|
||||||
, m_reverse(reverse)
|
|
||||||
{
|
|
||||||
SetValue(m_setting ^ m_reverse);
|
|
||||||
_connect_macro_(this, BoolSetting<W>::UpdateValue, wxEVT_COMMAND_RADIOBUTTON_SELECTED, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename W>
|
|
||||||
void BoolSetting<W>::UpdateValue(wxCommandEvent& ev)
|
|
||||||
{
|
|
||||||
m_setting = (ev.GetInt() != 0) ^ m_reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingChoice::SettingChoice(wxWindow* parent, int &setting, int num, const wxString choices[])
|
|
||||||
: wxChoice(parent, -1, wxDefaultPosition, wxDefaultSize, num, choices)
|
|
||||||
, m_setting(setting)
|
|
||||||
{
|
|
||||||
Select(m_setting);
|
|
||||||
_connect_macro_(this, SettingChoice::UpdateValue, wxEVT_COMMAND_CHOICE_SELECTED, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SettingChoice::UpdateValue(wxCommandEvent& ev)
|
|
||||||
{
|
|
||||||
m_setting = ev.GetInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoConfigDiag::CloseDiag(wxCommandEvent&)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoConfigDiag::VideoConfigDiag(wxWindow* parent)
|
|
||||||
: wxDialog(parent, -1, wxT("Dolphin Graphics Configuration"), wxDefaultPosition, wxDefaultSize)
|
|
||||||
{
|
|
||||||
VideoConfig &vconfig = g_Config;
|
|
||||||
|
|
||||||
wxNotebook* const notebook = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize);
|
|
||||||
|
|
||||||
// -- GENERAL --
|
|
||||||
{
|
|
||||||
wxPanel* const page_general = new wxPanel(notebook, -1, wxDefaultPosition);
|
|
||||||
notebook->AddPage(page_general, wxT("General"));
|
|
||||||
wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
// - basic
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_basic = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Basic"));
|
|
||||||
szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5);
|
|
||||||
wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5);
|
|
||||||
group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
// graphics api
|
|
||||||
{
|
|
||||||
const wxString gfxapi_choices[] = { wxT("Software [not present]"),
|
|
||||||
wxT("OpenGL [broken]"), wxT("Direct3D 9 [broken]"), wxT("Direct3D 11") };
|
|
||||||
|
|
||||||
szr_basic->Add(new wxStaticText(page_general, -1, wxT("Graphics API:")), 1, wxALIGN_CENTER_VERTICAL, 0);
|
|
||||||
wxChoice* const choice_gfxapi = new SettingChoice(page_general,
|
|
||||||
g_gfxapi, sizeof(gfxapi_choices)/sizeof(*gfxapi_choices), gfxapi_choices);
|
|
||||||
szr_basic->Add(choice_gfxapi, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for D3D only
|
|
||||||
// adapter
|
|
||||||
{
|
|
||||||
//szr_basic->Add(new wxStaticText(page_general, -1, wxT("Adapter:")), 1, wxALIGN_CENTER_VERTICAL, 5);
|
|
||||||
//wxChoice* const choice_adapter = new SettingChoice(page_general, vconfig.iAdapter);
|
|
||||||
//szr_basic->Add(choice_adapter, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// aspect-ratio
|
|
||||||
{
|
|
||||||
const wxString ar_choices[] = { wxT("Auto [recommended]"),
|
|
||||||
wxT("Force 16:9"), wxT("Force 4:3"), wxT("Strech to Window") };
|
|
||||||
|
|
||||||
szr_basic->Add(new wxStaticText(page_general, -1, wxT("Aspect ratio:")), 1, wxALIGN_CENTER_VERTICAL, 0);
|
|
||||||
wxChoice* const choice_aspect = new SettingChoice(page_general,
|
|
||||||
vconfig.iAspectRatio, sizeof(ar_choices)/sizeof(*ar_choices), ar_choices);
|
|
||||||
szr_basic->Add(choice_aspect, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// widescreen hack
|
|
||||||
{
|
|
||||||
szr_basic->AddStretchSpacer(1);
|
|
||||||
szr_basic->Add(new SettingCheckBox(page_general, wxT("Widescreen Hack"), vconfig.bWidescreenHack), 1, 0, 0);
|
|
||||||
szr_basic->AddStretchSpacer(1);
|
|
||||||
szr_basic->Add(new SettingCheckBox(page_general, wxT("V-Sync"), vconfig.bVSync), 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - EFB
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_efb = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("EFB"));
|
|
||||||
szr_general->Add(group_efb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
group_efb->Add(new SettingCheckBox(page_general, wxT("Enable CPU Access"), vconfig.bEFBAccessEnable), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
|
|
||||||
// EFB scale
|
|
||||||
{
|
|
||||||
// TODO: give this a label
|
|
||||||
const wxString efbscale_choices[] = { wxT("Fractional"), wxT("Integral [recommended]"),
|
|
||||||
wxT("1x"), wxT("2x"), wxT("3x")/*, wxT("4x")*/ };
|
|
||||||
|
|
||||||
wxChoice *const choice_efbscale = new SettingChoice(page_general,
|
|
||||||
vconfig.iEFBScale, sizeof(efbscale_choices)/sizeof(*efbscale_choices), efbscale_choices);
|
|
||||||
group_efb->Add(choice_efbscale, 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// EFB copy
|
|
||||||
wxStaticBoxSizer* const group_efbcopy = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Copy"));
|
|
||||||
group_efb->Add(group_efbcopy, 0, wxEXPAND | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
group_efbcopy->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bEFBCopyDisable, true), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
group_efbcopy->AddStretchSpacer(1);
|
|
||||||
group_efbcopy->Add(new SettingRadioButton(page_general, wxT("Texture"), vconfig.bCopyEFBToTexture, false, wxRB_GROUP), 0, wxRIGHT, 5);
|
|
||||||
group_efbcopy->Add(new SettingRadioButton(page_general, wxT("RAM"), vconfig.bCopyEFBToTexture, true), 0, wxRIGHT, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - safe texture cache
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Safe Texture Cache"));
|
|
||||||
szr_general->Add(group_safetex, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
// safe texture cache
|
|
||||||
group_safetex->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bSafeTextureCache), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
group_safetex->AddStretchSpacer(1);
|
|
||||||
// TODO: make these radio buttons functional
|
|
||||||
//group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Safe"),
|
|
||||||
// wxDefaultPosition, wxDefaultSize, wxRB_GROUP), 0, wxRIGHT, 5);
|
|
||||||
//group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Normal")), 0, wxRIGHT, 5);
|
|
||||||
//group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Fast")), 0, wxRIGHT, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
page_general->SetSizerAndFit(szr_general);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- ADVANCED --
|
|
||||||
{
|
|
||||||
wxPanel* const page_advanced = new wxPanel(notebook, -1, wxDefaultPosition);
|
|
||||||
notebook->AddPage(page_advanced, wxT("Advanced"));
|
|
||||||
wxBoxSizer* const szr_advanced = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
// - rendering
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_rendering = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Rendering"));
|
|
||||||
szr_advanced->Add(group_rendering, 0, wxEXPAND | wxALL, 5);
|
|
||||||
wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5);
|
|
||||||
group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Enable Wireframe"), vconfig.bWireFrame));
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Lighting"), vconfig.bDisableLighting));
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Textures"), vconfig.bDisableTexturing));
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Fog"), vconfig.bDisableFog));
|
|
||||||
szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Dest. Alpha Pass"), vconfig.bDstAlphaPass));
|
|
||||||
}
|
|
||||||
|
|
||||||
// - info
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_info = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Overlay Information"));
|
|
||||||
szr_advanced->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5);
|
|
||||||
group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
szr_info->Add(new SettingCheckBox(page_advanced, wxT("Show FPS"), vconfig.bShowFPS));
|
|
||||||
szr_info->Add(new SettingCheckBox(page_advanced, wxT("Various Statistics"), vconfig.bOverlayStats));
|
|
||||||
szr_info->Add(new SettingCheckBox(page_advanced, wxT("Projection Stats"), vconfig.bOverlayProjStats));
|
|
||||||
szr_info->Add(new SettingCheckBox(page_advanced, wxT("Texture Format"), vconfig.bTexFmtOverlayEnable));
|
|
||||||
szr_info->Add(new SettingCheckBox(page_advanced, wxT("EFB Copy Regions"), vconfig.bShowEFBCopyRegions));
|
|
||||||
}
|
|
||||||
|
|
||||||
// - XFB
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_xfb = new wxStaticBoxSizer(wxHORIZONTAL, page_advanced, wxT("XFB"));
|
|
||||||
szr_advanced->Add(group_xfb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
group_xfb->Add(new SettingCheckBox(page_advanced, wxT("Enable"), vconfig.bUseXFB), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
group_xfb->AddStretchSpacer(1);
|
|
||||||
group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Virtual"), vconfig.bUseRealXFB, true, wxRB_GROUP), 0, wxRIGHT, 5);
|
|
||||||
group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Real"), vconfig.bUseRealXFB), 0, wxRIGHT, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// - utility
|
|
||||||
{
|
|
||||||
wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Utility"));
|
|
||||||
szr_advanced->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5);
|
|
||||||
group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Textures"), vconfig.bDumpTextures));
|
|
||||||
szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Load Hi-Res Textures"), vconfig.bHiresTextures));
|
|
||||||
szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump EFB Target"), vconfig.bDumpEFBTarget));
|
|
||||||
szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Frames"), vconfig.bDumpFrames));
|
|
||||||
szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Free Look"), vconfig.bFreeLook));
|
|
||||||
}
|
|
||||||
|
|
||||||
// stuff to move/remove
|
|
||||||
{
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Load Native Mipmaps"), vconfig.bUseNativeMips), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("EFB Scaled Copy"), vconfig.bCopyEFBScaled), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Auto Scale"), vconfig.bAutoScale), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Crop"), vconfig.bCrop), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable OpenCL"), vconfig.bEnableOpenCL), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable Display List Caching"), vconfig.bDlistCachingEnable), 0, wxBOTTOM | wxLEFT, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
page_advanced->SetSizerAndFit(szr_advanced);
|
|
||||||
}
|
|
||||||
|
|
||||||
wxButton* const btn_close = new wxButton(this, -1, wxT("Close"), wxDefaultPosition);
|
|
||||||
_connect_macro_(btn_close, VideoConfigDiag::CloseDiag, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
|
||||||
|
|
||||||
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
|
|
||||||
szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
|
|
||||||
szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
|
|
||||||
|
|
||||||
SetSizerAndFit(szr_main);
|
|
||||||
Center();
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
|
|
||||||
#ifndef _CONFIG_DIAG_H_
|
|
||||||
#define _CONFIG_DIAG_H_
|
|
||||||
|
|
||||||
#include <wx/wx.h>
|
|
||||||
#include <wx/textctrl.h>
|
|
||||||
#include <wx/button.h>
|
|
||||||
#include <wx/stattext.h>
|
|
||||||
#include <wx/combobox.h>
|
|
||||||
#include <wx/checkbox.h>
|
|
||||||
#include <wx/notebook.h>
|
|
||||||
#include <wx/panel.h>
|
|
||||||
#include <wx/spinctrl.h>
|
|
||||||
|
|
||||||
template <typename W>
|
|
||||||
class BoolSetting : public W
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse = false, long style = 0);
|
|
||||||
void UpdateValue(wxCommandEvent& ev);
|
|
||||||
private:
|
|
||||||
bool &m_setting;
|
|
||||||
const bool m_reverse;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SettingChoice : public wxChoice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SettingChoice(wxWindow* parent, int &setting, int num = 0, const wxString choices[] = NULL);
|
|
||||||
void UpdateValue(wxCommandEvent& ev);
|
|
||||||
private:
|
|
||||||
int &m_setting;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VideoConfigDiag : public wxDialog
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VideoConfigDiag(wxWindow* parent);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void CloseDiag(wxCommandEvent&);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue