mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Put Plugins/ in Core/, rename to VideoBackends
This commit is contained in:
53
Source/Core/VideoBackends/Software/CMakeLists.txt
Normal file
53
Source/Core/VideoBackends/Software/CMakeLists.txt
Normal file
@ -0,0 +1,53 @@
|
||||
set(SRCS Src/BPMemLoader.cpp
|
||||
Src/Clipper.cpp
|
||||
Src/SWCommandProcessor.cpp
|
||||
Src/CPMemLoader.cpp
|
||||
Src/DebugUtil.cpp
|
||||
Src/EfbCopy.cpp
|
||||
Src/EfbInterface.cpp
|
||||
Src/HwRasterizer.cpp
|
||||
Src/SWmain.cpp
|
||||
Src/OpcodeDecoder.cpp
|
||||
Src/SWPixelEngine.cpp
|
||||
Src/Rasterizer.cpp
|
||||
Src/SWRenderer.cpp
|
||||
Src/SetupUnit.cpp
|
||||
Src/SWStatistics.cpp
|
||||
Src/Tev.cpp
|
||||
Src/TextureEncoder.cpp
|
||||
Src/TextureSampler.cpp
|
||||
Src/TransformUnit.cpp
|
||||
Src/SWVertexLoader.cpp
|
||||
Src/SWVideoConfig.cpp
|
||||
Src/XFMemLoader.cpp)
|
||||
|
||||
if(wxWidgets_FOUND)
|
||||
set(SRCS ${SRCS} Src/VideoConfigDialog.cpp)
|
||||
endif(wxWidgets_FOUND)
|
||||
|
||||
set(LIBS videocommon
|
||||
SOIL
|
||||
common
|
||||
${X11_LIBRARIES}
|
||||
${wxWidgets_LIBRARIES})
|
||||
if(USE_EGL)
|
||||
set(LIBS ${LIBS}
|
||||
EGL)
|
||||
endif()
|
||||
|
||||
if(USE_GLES)
|
||||
set(SRCS ${SRCS} ../OGL/Src/GLUtil.cpp)
|
||||
set(LIBS ${LIBS}
|
||||
GLESv2)
|
||||
else()
|
||||
set(SRCS ${SRCS} Src/RasterFont.cpp)
|
||||
set(LIBS ${LIBS}
|
||||
GLEW
|
||||
${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
if(NOT (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
||||
set(LIBS ${LIBS} clrun)
|
||||
endif()
|
||||
|
||||
add_library(videosoftware STATIC ${SRCS})
|
||||
target_link_libraries(videosoftware ${LIBS})
|
244
Source/Core/VideoBackends/Software/Software.vcxproj
Normal file
244
Source/Core/VideoBackends/Software/Software.vcxproj
Normal file
@ -0,0 +1,244 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="DebugFast|Win32">
|
||||
<Configuration>DebugFast</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="DebugFast|x64">
|
||||
<Configuration>DebugFast</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{9E9DA440-E9AD-413C-B648-91030E792211}</ProjectGuid>
|
||||
<RootNamespace>VideoSoftware</RootNamespace>
|
||||
<ProjectName>VideoSoftware</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_Debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_Debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_Release.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_Release.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_DebugFast.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\VSProps\Base.props" />
|
||||
<Import Project="..\..\VSProps\CodeGen_DebugFast.props" />
|
||||
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;glew32s.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;glew64s.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glew32s.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glew64s.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\GLew\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\Include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\BPMemLoader.cpp" />
|
||||
<ClCompile Include="Src\Clipper.cpp" />
|
||||
<ClCompile Include="Src\SWCommandProcessor.cpp" />
|
||||
<ClCompile Include="Src\CPMemLoader.cpp" />
|
||||
<ClCompile Include="Src\DebugUtil.cpp" />
|
||||
<ClCompile Include="Src\EfbCopy.cpp" />
|
||||
<ClCompile Include="Src\EfbInterface.cpp" />
|
||||
<ClCompile Include="Src\HwRasterizer.cpp" />
|
||||
<ClCompile Include="Src\SWmain.cpp" />
|
||||
<ClCompile Include="Src\OpcodeDecoder.cpp" />
|
||||
<ClCompile Include="Src\SWPixelEngine.cpp" />
|
||||
<ClCompile Include="Src\Rasterizer.cpp" />
|
||||
<ClCompile Include="Src\RasterFont.cpp" />
|
||||
<ClCompile Include="Src\SWRenderer.cpp" />
|
||||
<ClCompile Include="Src\SetupUnit.cpp" />
|
||||
<ClCompile Include="Src\SWStatistics.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\SWVideoConfig.cpp" />
|
||||
<ClCompile Include="Src\Tev.cpp" />
|
||||
<ClCompile Include="Src\TextureEncoder.cpp" />
|
||||
<ClCompile Include="Src\TextureSampler.cpp" />
|
||||
<ClCompile Include="Src\TransformUnit.cpp" />
|
||||
<ClCompile Include="Src\SWVertexLoader.cpp" />
|
||||
<ClCompile Include="Src\VideoConfigDialog.cpp" />
|
||||
<ClCompile Include="Src\XFMemLoader.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\BPMemLoader.h" />
|
||||
<ClInclude Include="Src\Clipper.h" />
|
||||
<ClInclude Include="Src\SWCommandProcessor.h" />
|
||||
<ClInclude Include="Src\CPMemLoader.h" />
|
||||
<ClInclude Include="Src\DebugUtil.h" />
|
||||
<ClInclude Include="Src\EfbCopy.h" />
|
||||
<ClInclude Include="Src\EfbInterface.h" />
|
||||
<ClInclude Include="Src\HwRasterizer.h" />
|
||||
<ClInclude Include="Src\NativeVertexFormat.h" />
|
||||
<ClInclude Include="Src\OpcodeDecoder.h" />
|
||||
<ClInclude Include="Src\SWPixelEngine.h" />
|
||||
<ClInclude Include="Src\Rasterizer.h" />
|
||||
<ClInclude Include="Src\RasterFont.h" />
|
||||
<ClInclude Include="Src\SWRenderer.h" />
|
||||
<ClInclude Include="Src\SetupUnit.h" />
|
||||
<ClInclude Include="Src\SWStatistics.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\SWVideoConfig.h" />
|
||||
<ClInclude Include="Src\Tev.h" />
|
||||
<ClInclude Include="Src\TextureEncoder.h" />
|
||||
<ClInclude Include="Src\TextureSampler.h" />
|
||||
<ClInclude Include="Src\TransformUnit.h" />
|
||||
<ClInclude Include="Src\Vec3.h" />
|
||||
<ClInclude Include="Src\SWVertexLoader.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\VideoConfigDialog.h" />
|
||||
<ClInclude Include="Src\XFMemLoader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\VideoCommon\VideoCommon.vcxproj">
|
||||
<Project>{3e5c4e02-1ba9-4776-bdbe-e3f91ffa34cf}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
67
Source/Core/VideoBackends/Software/Software.vcxproj.filters
Normal file
67
Source/Core/VideoBackends/Software/Software.vcxproj.filters
Normal file
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\BPMemLoader.cpp" />
|
||||
<ClCompile Include="Src\Clipper.cpp" />
|
||||
<ClCompile Include="Src\SWCommandProcessor.cpp" />
|
||||
<ClCompile Include="Src\CPMemLoader.cpp" />
|
||||
<ClCompile Include="Src\DebugUtil.cpp" />
|
||||
<ClCompile Include="Src\EfbCopy.cpp" />
|
||||
<ClCompile Include="Src\EfbInterface.cpp" />
|
||||
<ClCompile Include="Src\HwRasterizer.cpp" />
|
||||
<ClCompile Include="Src\SWmain.cpp" />
|
||||
<ClCompile Include="Src\OpcodeDecoder.cpp" />
|
||||
<ClCompile Include="Src\SWPixelEngine.cpp" />
|
||||
<ClCompile Include="Src\Rasterizer.cpp" />
|
||||
<ClCompile Include="Src\RasterFont.cpp" />
|
||||
<ClCompile Include="Src\SWRenderer.cpp" />
|
||||
<ClCompile Include="Src\SetupUnit.cpp" />
|
||||
<ClCompile Include="Src\SWStatistics.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp" />
|
||||
<ClCompile Include="Src\SWVideoConfig.cpp" />
|
||||
<ClCompile Include="Src\Tev.cpp" />
|
||||
<ClCompile Include="Src\TextureEncoder.cpp" />
|
||||
<ClCompile Include="Src\TextureSampler.cpp" />
|
||||
<ClCompile Include="Src\TransformUnit.cpp" />
|
||||
<ClCompile Include="Src\SWVertexLoader.cpp" />
|
||||
<ClCompile Include="Src\VideoConfigDialog.cpp" />
|
||||
<ClCompile Include="Src\XFMemLoader.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\BPMemLoader.h" />
|
||||
<ClInclude Include="Src\Clipper.h" />
|
||||
<ClInclude Include="Src\SWCommandProcessor.h" />
|
||||
<ClInclude Include="Src\CPMemLoader.h" />
|
||||
<ClInclude Include="Src\DebugUtil.h" />
|
||||
<ClInclude Include="Src\EfbCopy.h" />
|
||||
<ClInclude Include="Src\EfbInterface.h" />
|
||||
<ClInclude Include="Src\HwRasterizer.h" />
|
||||
<ClInclude Include="Src\NativeVertexFormat.h" />
|
||||
<ClInclude Include="Src\OpcodeDecoder.h" />
|
||||
<ClInclude Include="Src\SWPixelEngine.h" />
|
||||
<ClInclude Include="Src\Rasterizer.h" />
|
||||
<ClInclude Include="Src\RasterFont.h" />
|
||||
<ClInclude Include="Src\SWRenderer.h" />
|
||||
<ClInclude Include="Src\SetupUnit.h" />
|
||||
<ClInclude Include="Src\SWStatistics.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\SWVideoConfig.h" />
|
||||
<ClInclude Include="Src\Tev.h" />
|
||||
<ClInclude Include="Src\TextureEncoder.h" />
|
||||
<ClInclude Include="Src\TextureSampler.h" />
|
||||
<ClInclude Include="Src\TransformUnit.h" />
|
||||
<ClInclude Include="Src\Vec3.h" />
|
||||
<ClInclude Include="Src\SWVertexLoader.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\VideoConfigDialog.h" />
|
||||
<ClInclude Include="Src\XFMemLoader.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Win32">
|
||||
<UniqueIdentifier>{081288cb-a63b-4ae9-93eb-e668568520b8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
188
Source/Core/VideoBackends/Software/Src/BPMemLoader.cpp
Normal file
188
Source/Core/VideoBackends/Software/Src/BPMemLoader.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "TextureDecoder.h"
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "EfbCopy.h"
|
||||
#include "Rasterizer.h"
|
||||
#include "SWPixelEngine.h"
|
||||
#include "Tev.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "Core.h"
|
||||
|
||||
|
||||
void InitBPMemory()
|
||||
{
|
||||
memset(&bpmem, 0, sizeof(bpmem));
|
||||
bpmem.bpMask = 0xFFFFFF;
|
||||
}
|
||||
|
||||
void SWLoadBPReg(u32 value)
|
||||
{
|
||||
//handle the mask register
|
||||
int address = value >> 24;
|
||||
int oldval = ((u32*)&bpmem)[address];
|
||||
int newval = (oldval & ~bpmem.bpMask) | (value & bpmem.bpMask);
|
||||
|
||||
((u32*)&bpmem)[address] = newval;
|
||||
|
||||
//reset the mask register
|
||||
if (address != 0xFE)
|
||||
bpmem.bpMask = 0xFFFFFF;
|
||||
|
||||
SWBPWritten(address, newval);
|
||||
}
|
||||
|
||||
void SWBPWritten(int address, int newvalue)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case BPMEM_SCISSORTL:
|
||||
case BPMEM_SCISSORBR:
|
||||
case BPMEM_SCISSOROFFSET:
|
||||
Rasterizer::SetScissor();
|
||||
break;
|
||||
case BPMEM_SETDRAWDONE: // This is called when the game is done drawing (eg: like in DX: Begin(); Draw(); End();)
|
||||
switch (bpmem.drawdone & 0xFF)
|
||||
{
|
||||
case 0x02:
|
||||
SWPixelEngine::SetFinish(); // may generate interrupt
|
||||
DEBUG_LOG(VIDEO, "GXSetDrawDone SetPEFinish (value: 0x%02X)", (bpmem.drawdone & 0xFFFF));
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN_LOG(VIDEO, "GXSetDrawDone ??? (value 0x%02X)", (bpmem.drawdone & 0xFFFF));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BPMEM_PE_TOKEN_ID: // Pixel Engine Token ID
|
||||
DEBUG_LOG(VIDEO, "SetPEToken 0x%04x", (bpmem.petoken & 0xFFFF));
|
||||
SWPixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), false);
|
||||
break;
|
||||
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
|
||||
DEBUG_LOG(VIDEO, "SetPEToken + INT 0x%04x", (bpmem.petokenint & 0xFFFF));
|
||||
SWPixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), true);
|
||||
break;
|
||||
case BPMEM_TRIGGER_EFB_COPY:
|
||||
EfbCopy::CopyEfb();
|
||||
break;
|
||||
case BPMEM_CLEARBBOX1:
|
||||
SWPixelEngine::pereg.boxRight = newvalue >> 10;
|
||||
SWPixelEngine::pereg.boxLeft = newvalue & 0x3ff;
|
||||
break;
|
||||
case BPMEM_CLEARBBOX2:
|
||||
SWPixelEngine::pereg.boxBottom = newvalue >> 10;
|
||||
SWPixelEngine::pereg.boxTop = newvalue & 0x3ff;
|
||||
break;
|
||||
case BPMEM_CLEAR_PIXEL_PERF:
|
||||
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
|
||||
SWPixelEngine::pereg.perfZcompInputZcomplocLo = 0;
|
||||
SWPixelEngine::pereg.perfZcompInputZcomplocHi = 0;
|
||||
SWPixelEngine::pereg.perfZcompOutputZcomplocLo = 0;
|
||||
SWPixelEngine::pereg.perfZcompOutputZcomplocHi = 0;
|
||||
SWPixelEngine::pereg.perfZcompInputLo = 0;
|
||||
SWPixelEngine::pereg.perfZcompInputHi = 0;
|
||||
SWPixelEngine::pereg.perfZcompOutputLo = 0;
|
||||
SWPixelEngine::pereg.perfZcompOutputHi = 0;
|
||||
SWPixelEngine::pereg.perfBlendInputLo = 0;
|
||||
SWPixelEngine::pereg.perfBlendInputHi = 0;
|
||||
SWPixelEngine::pereg.perfEfbCopyClocksLo = 0;
|
||||
SWPixelEngine::pereg.perfEfbCopyClocksHi = 0;
|
||||
break;
|
||||
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
|
||||
break;
|
||||
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
|
||||
{
|
||||
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
|
||||
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
|
||||
|
||||
u8 *ptr = 0;
|
||||
|
||||
// TODO - figure out a cleaner way.
|
||||
if (Core::g_CoreStartupParameter.bWii)
|
||||
ptr = Memory::GetPointer(bpmem.tmem_config.tlut_src << 5);
|
||||
else
|
||||
ptr = Memory::GetPointer((bpmem.tmem_config.tlut_src & 0xFFFFF) << 5);
|
||||
|
||||
if (ptr)
|
||||
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
|
||||
else
|
||||
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tmem_config.tlut_src, bpmem.tmem_config.tlut_src << 5, (bpmem.tmem_config.tlut_src & 0xFFFFF)<< 5);
|
||||
break;
|
||||
}
|
||||
|
||||
case BPMEM_PRELOAD_MODE:
|
||||
if (newvalue != 0)
|
||||
{
|
||||
// TODO: Not quite sure if this is completely correct (likely not)
|
||||
// NOTE: libogc's implementation of GX_PreloadEntireTexture seems flawed, so it's not necessarily a good reference for RE'ing this feature.
|
||||
|
||||
BPS_TmemConfig& tmem_cfg = bpmem.tmem_config;
|
||||
u8* src_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5); // TODO: Should we add mask here on GC?
|
||||
u32 size = tmem_cfg.preload_tile_info.count * TMEM_LINE_SIZE;
|
||||
u32 tmem_addr_even = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE;
|
||||
|
||||
if (tmem_cfg.preload_tile_info.type != 3)
|
||||
{
|
||||
if (tmem_addr_even + size > TMEM_SIZE)
|
||||
size = TMEM_SIZE - tmem_addr_even;
|
||||
|
||||
memcpy(texMem + tmem_addr_even, src_ptr, size);
|
||||
}
|
||||
else // RGBA8 tiles (and CI14, but that might just be stupid libogc!)
|
||||
{
|
||||
// AR and GB tiles are stored in separate TMEM banks => can't use a single memcpy for everything
|
||||
u32 tmem_addr_odd = tmem_cfg.preload_tmem_odd * TMEM_LINE_SIZE;
|
||||
|
||||
for (unsigned int i = 0; i < tmem_cfg.preload_tile_info.count; ++i)
|
||||
{
|
||||
if (tmem_addr_even + TMEM_LINE_SIZE > TMEM_SIZE ||
|
||||
tmem_addr_odd + TMEM_LINE_SIZE > TMEM_SIZE)
|
||||
break;
|
||||
|
||||
memcpy(texMem + tmem_addr_even, src_ptr, TMEM_LINE_SIZE);
|
||||
memcpy(texMem + tmem_addr_odd, src_ptr + TMEM_LINE_SIZE, TMEM_LINE_SIZE);
|
||||
tmem_addr_even += TMEM_LINE_SIZE;
|
||||
tmem_addr_odd += TMEM_LINE_SIZE;
|
||||
src_ptr += TMEM_LINE_SIZE * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BPMEM_TEV_REGISTER_L: // Reg 1
|
||||
case BPMEM_TEV_REGISTER_L+2: // Reg 2
|
||||
case BPMEM_TEV_REGISTER_L+4: // Reg 3
|
||||
case BPMEM_TEV_REGISTER_L+6: // Reg 4
|
||||
{
|
||||
int regNum = (address >> 1 ) & 0x3;
|
||||
ColReg& reg = bpmem.tevregs[regNum].low;
|
||||
bool konst = reg.type;
|
||||
|
||||
Rasterizer::SetTevReg(regNum, Tev::ALP_C, konst, reg.b); // A
|
||||
Rasterizer::SetTevReg(regNum, Tev::RED_C, konst, reg.a); // R
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BPMEM_TEV_REGISTER_H: // Reg 1
|
||||
case BPMEM_TEV_REGISTER_H+2: // Reg 2
|
||||
case BPMEM_TEV_REGISTER_H+4: // Reg 3
|
||||
case BPMEM_TEV_REGISTER_H+6: // Reg 4
|
||||
{
|
||||
int regNum = (address >> 1 ) & 0x3;
|
||||
ColReg& reg = bpmem.tevregs[regNum].high;
|
||||
bool konst = reg.type;
|
||||
|
||||
Rasterizer::SetTevReg(regNum, Tev::GRN_C, konst, reg.b); // G
|
||||
Rasterizer::SetTevReg(regNum, Tev::BLU_C, konst, reg.a); // B
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
16
Source/Core/VideoBackends/Software/Src/BPMemLoader.h
Normal file
16
Source/Core/VideoBackends/Software/Src/BPMemLoader.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _BPMEMLOADER_H_
|
||||
#define _BPMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "BPMemory.h"
|
||||
|
||||
void InitBPMemory();
|
||||
void SWBPWritten(int address, int newvalue);
|
||||
void SWLoadBPReg(u32 value);
|
||||
|
||||
#endif
|
58
Source/Core/VideoBackends/Software/Src/CPMemLoader.cpp
Normal file
58
Source/Core/VideoBackends/Software/Src/CPMemLoader.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
#include "CPMemLoader.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
|
||||
void SWLoadCPReg(u32 sub_cmd, u32 value)
|
||||
{
|
||||
switch (sub_cmd & 0xF0)
|
||||
{
|
||||
case 0x30:
|
||||
MatrixIndexA.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
MatrixIndexB.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
g_VtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
|
||||
g_VtxDesc.Hex |= value;
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
g_VtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
|
||||
g_VtxDesc.Hex |= (u64)value << 17;
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
_assert_((sub_cmd & 0x0F) < 8);
|
||||
g_VtxAttr[sub_cmd & 7].g0.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
_assert_((sub_cmd & 0x0F) < 8);
|
||||
g_VtxAttr[sub_cmd & 7].g1.Hex = value;
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
_assert_((sub_cmd & 0x0F) < 8);
|
||||
g_VtxAttr[sub_cmd & 7].g2.Hex = value;
|
||||
break;
|
||||
|
||||
// Pointers to vertex arrays in GC RAM
|
||||
case 0xA0:
|
||||
arraybases[sub_cmd & 0xF] = value;
|
||||
cached_arraybases[sub_cmd & 0xF] = Memory::GetPointer(value);
|
||||
break;
|
||||
|
||||
case 0xB0:
|
||||
arraystrides[sub_cmd & 0xF] = value & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
14
Source/Core/VideoBackends/Software/Src/CPMemLoader.h
Normal file
14
Source/Core/VideoBackends/Software/Src/CPMemLoader.h
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _CPMEMLOADER_H_
|
||||
#define _CPMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "CPMemory.h"
|
||||
|
||||
void SWLoadCPReg(u32 sub_cmd, u32 value);
|
||||
|
||||
#endif
|
438
Source/Core/VideoBackends/Software/Src/Clipper.cpp
Normal file
438
Source/Core/VideoBackends/Software/Src/Clipper.cpp
Normal file
@ -0,0 +1,438 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
/*
|
||||
Portions of this file are based off work by Markus Trenkwalder.
|
||||
Copyright (c) 2007, 2008 Markus Trenkwalder
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the library's copyright owner nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "Clipper.h"
|
||||
#include "Rasterizer.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "SWStatistics.h"
|
||||
|
||||
|
||||
namespace Clipper
|
||||
{
|
||||
enum { NUM_CLIPPED_VERTICES = 33, NUM_INDICES = NUM_CLIPPED_VERTICES + 3 };
|
||||
|
||||
float m_ViewOffset[2];
|
||||
|
||||
OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
|
||||
OutputVertexData *Vertices[NUM_INDICES];
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoArray(m_ViewOffset,2);
|
||||
for (int i = 0; i< NUM_CLIPPED_VERTICES; ++i)
|
||||
ClippedVertices[i].DoState(p);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
|
||||
Vertices[i+3] = &ClippedVertices[i];
|
||||
}
|
||||
|
||||
void SetViewOffset()
|
||||
{
|
||||
m_ViewOffset[0] = swxfregs.viewport.xOrig - 342;
|
||||
m_ViewOffset[1] = swxfregs.viewport.yOrig - 342;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
SKIP_FLAG = -1,
|
||||
CLIP_POS_X_BIT = 0x01,
|
||||
CLIP_NEG_X_BIT = 0x02,
|
||||
CLIP_POS_Y_BIT = 0x04,
|
||||
CLIP_NEG_Y_BIT = 0x08,
|
||||
CLIP_POS_Z_BIT = 0x10,
|
||||
CLIP_NEG_Z_BIT = 0x20
|
||||
};
|
||||
|
||||
static inline int CalcClipMask(OutputVertexData *v)
|
||||
{
|
||||
int cmask = 0;
|
||||
Vec4 pos = v->projectedPosition;
|
||||
if (pos.w - pos.x < 0) cmask |= CLIP_POS_X_BIT;
|
||||
if (pos.x + pos.w < 0) cmask |= CLIP_NEG_X_BIT;
|
||||
if (pos.w - pos.y < 0) cmask |= CLIP_POS_Y_BIT;
|
||||
if (pos.y + pos.w < 0) cmask |= CLIP_NEG_Y_BIT;
|
||||
if (pos.w * pos.z > 0) cmask |= CLIP_POS_Z_BIT;
|
||||
if (pos.z + pos.w < 0) cmask |= CLIP_NEG_Z_BIT;
|
||||
return cmask;
|
||||
}
|
||||
|
||||
static inline void AddInterpolatedVertex(float t, int out, int in, int& numVertices)
|
||||
{
|
||||
Vertices[numVertices]->Lerp(t, Vertices[out], Vertices[in]);
|
||||
numVertices++;
|
||||
}
|
||||
|
||||
#define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0))
|
||||
|
||||
#define CLIP_DOTPROD(I, A, B, C, D) \
|
||||
(Vertices[I]->projectedPosition.x * A + Vertices[I]->projectedPosition.y * B + Vertices[I]->projectedPosition.z * C + Vertices[I]->projectedPosition.w * D)
|
||||
|
||||
#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) { \
|
||||
int idxPrev = inlist[0]; \
|
||||
float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
|
||||
int outcount = 0; \
|
||||
\
|
||||
inlist[n] = inlist[0]; \
|
||||
for (int j = 1; j <= n; j++) { \
|
||||
int idx = inlist[j]; \
|
||||
float dp = CLIP_DOTPROD(idx, A, B, C, D ); \
|
||||
if (dpPrev >= 0) { \
|
||||
outlist[outcount++] = idxPrev; \
|
||||
} \
|
||||
\
|
||||
if (DIFFERENT_SIGNS(dp, dpPrev)) { \
|
||||
if (dp < 0) { \
|
||||
float t = dp / (dp - dpPrev); \
|
||||
AddInterpolatedVertex(t, idx, idxPrev, numVertices); \
|
||||
} else { \
|
||||
float t = dpPrev / (dpPrev - dp); \
|
||||
AddInterpolatedVertex(t, idxPrev, idx, numVertices); \
|
||||
} \
|
||||
outlist[outcount++] = numVertices - 1; \
|
||||
} \
|
||||
\
|
||||
idxPrev = idx; \
|
||||
dpPrev = dp; \
|
||||
} \
|
||||
\
|
||||
if (outcount < 3) \
|
||||
continue; \
|
||||
\
|
||||
{ \
|
||||
int *tmp = inlist; \
|
||||
inlist = outlist; \
|
||||
outlist = tmp; \
|
||||
n = outcount; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LINE_CLIP(PLANE_BIT, A, B, C, D ) \
|
||||
{ \
|
||||
if (mask & PLANE_BIT) { \
|
||||
const float dp0 = CLIP_DOTPROD( 0, A, B, C, D ); \
|
||||
const float dp1 = CLIP_DOTPROD( 1, A, B, C, D ); \
|
||||
const bool neg_dp0 = dp0 < 0; \
|
||||
const bool neg_dp1 = dp1 < 0; \
|
||||
\
|
||||
if (neg_dp0 && neg_dp1) \
|
||||
return; \
|
||||
\
|
||||
if (neg_dp1) { \
|
||||
float t = dp1 / (dp1 - dp0); \
|
||||
if (t > t1) t1 = t; \
|
||||
} else if (neg_dp0) { \
|
||||
float t = dp0 / (dp0 - dp1); \
|
||||
if (t > t0) t0 = t; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
void ClipTriangle(int *indices, int &numIndices)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
mask |= CalcClipMask(Vertices[0]);
|
||||
mask |= CalcClipMask(Vertices[1]);
|
||||
mask |= CalcClipMask(Vertices[2]);
|
||||
|
||||
if (mask != 0)
|
||||
{
|
||||
for(int i = 0; i < 3; i += 3)
|
||||
{
|
||||
int vlist[2][2*6+1];
|
||||
int *inlist = vlist[0], *outlist = vlist[1];
|
||||
int n = 3;
|
||||
int numVertices = 3;
|
||||
|
||||
inlist[0] = 0;
|
||||
inlist[1] = 1;
|
||||
inlist[2] = 2;
|
||||
|
||||
// mark this triangle as unused in case it should be completely
|
||||
// clipped
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
indices[2] = SKIP_FLAG;
|
||||
|
||||
POLY_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
POLY_CLIP(CLIP_POS_Z_BIT, 0, 0, 0, 1);
|
||||
POLY_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
INCSTAT(swstats.thisFrame.numTrianglesClipped);
|
||||
|
||||
// transform the poly in inlist into triangles
|
||||
indices[0] = inlist[0];
|
||||
indices[1] = inlist[1];
|
||||
indices[2] = inlist[2];
|
||||
for (int j = 3; j < n; ++j) {
|
||||
indices[numIndices++] = inlist[0];
|
||||
indices[numIndices++] = inlist[j - 1];
|
||||
indices[numIndices++] = inlist[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClipLine(int *indices)
|
||||
{
|
||||
int mask = 0;
|
||||
int clip_mask[2] = { 0, 0 };
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
clip_mask[i] = CalcClipMask(Vertices[i]);
|
||||
mask |= clip_mask[i];
|
||||
}
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
float t0 = 0;
|
||||
float t1 = 0;
|
||||
|
||||
// Mark unused in case of early termination
|
||||
// of the macros below. (When fully clipped)
|
||||
indices[0] = SKIP_FLAG;
|
||||
indices[1] = SKIP_FLAG;
|
||||
|
||||
LINE_CLIP(CLIP_POS_X_BIT, -1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_X_BIT, 1, 0, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Y_BIT, 0, -1, 0, 1);
|
||||
LINE_CLIP(CLIP_NEG_Y_BIT, 0, 1, 0, 1);
|
||||
LINE_CLIP(CLIP_POS_Z_BIT, 0, 0, -1, 1);
|
||||
LINE_CLIP(CLIP_NEG_Z_BIT, 0, 0, 1, 1);
|
||||
|
||||
// Restore the old values as this line
|
||||
// was not fully clipped.
|
||||
indices[0] = 0;
|
||||
indices[1] = 1;
|
||||
|
||||
int numVertices = 2;
|
||||
|
||||
if (clip_mask[0])
|
||||
{
|
||||
indices[0] = numVertices;
|
||||
AddInterpolatedVertex(t0, 0, 1, numVertices);
|
||||
}
|
||||
|
||||
if (clip_mask[1])
|
||||
{
|
||||
indices[1] = numVertices;
|
||||
AddInterpolatedVertex(t1, 1, 0, numVertices);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.numTrianglesIn)
|
||||
|
||||
bool backface;
|
||||
|
||||
if(!CullTest(v0, v1, v2, backface))
|
||||
return;
|
||||
|
||||
int indices[NUM_INDICES] = { 0, 1, 2, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG,
|
||||
SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG, SKIP_FLAG };
|
||||
int numIndices = 3;
|
||||
|
||||
if (backface)
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v2;
|
||||
Vertices[2] = v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vertices[0] = v0;
|
||||
Vertices[1] = v1;
|
||||
Vertices[2] = v2;
|
||||
}
|
||||
|
||||
ClipTriangle(indices, numIndices);
|
||||
|
||||
for(int i = 0; i+3 <= numIndices; i+=3)
|
||||
{
|
||||
_assert_(i < NUM_INDICES);
|
||||
if(indices[i] != SKIP_FLAG)
|
||||
{
|
||||
PerspectiveDivide(Vertices[indices[i]]);
|
||||
PerspectiveDivide(Vertices[indices[i+1]]);
|
||||
PerspectiveDivide(Vertices[indices[i+2]]);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(Vertices[indices[i]], Vertices[indices[i+1]], Vertices[indices[i+2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyVertex(OutputVertexData *dst, OutputVertexData *src, float dx, float dy, unsigned int sOffset)
|
||||
{
|
||||
dst->screenPosition.x = src->screenPosition.x + dx;
|
||||
dst->screenPosition.y = src->screenPosition.y + dy;
|
||||
dst->screenPosition.z = src->screenPosition.z;
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
dst->normal[i] = src->normal[i];
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
dst->color[0][i] = src->color[0][i];
|
||||
|
||||
// todo - s offset
|
||||
for (int i = 0; i < 8; ++i)
|
||||
dst->texCoords[i] = src->texCoords[i];
|
||||
}
|
||||
|
||||
void ProcessLine(OutputVertexData *lineV0, OutputVertexData *lineV1)
|
||||
{
|
||||
int indices[4] = { 0, 1, SKIP_FLAG, SKIP_FLAG };
|
||||
|
||||
Vertices[0] = lineV0;
|
||||
Vertices[1] = lineV1;
|
||||
|
||||
// point to a valid vertex to store to when clipping
|
||||
Vertices[2] = &ClippedVertices[17];
|
||||
|
||||
ClipLine(indices);
|
||||
|
||||
if(indices[0] != SKIP_FLAG)
|
||||
{
|
||||
OutputVertexData *v0 = Vertices[indices[0]];
|
||||
OutputVertexData *v1 = Vertices[indices[1]];
|
||||
|
||||
PerspectiveDivide(v0);
|
||||
PerspectiveDivide(v1);
|
||||
|
||||
float dx = v1->screenPosition.x - v0->screenPosition.x;
|
||||
float dy = v1->screenPosition.y - v0->screenPosition.y;
|
||||
|
||||
float screenDx = 0;
|
||||
float screenDy = 0;
|
||||
|
||||
if(fabsf(dx) > fabsf(dy))
|
||||
{
|
||||
if(dx > 0)
|
||||
screenDy = bpmem.lineptwidth.linesize / -12.0f;
|
||||
else
|
||||
screenDy = bpmem.lineptwidth.linesize / 12.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dy > 0)
|
||||
screenDx = bpmem.lineptwidth.linesize / 12.0f;
|
||||
else
|
||||
screenDx = bpmem.lineptwidth.linesize / -12.0f;
|
||||
}
|
||||
|
||||
OutputVertexData triangle[3];
|
||||
|
||||
CopyVertex(&triangle[0], v0, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[1], v1, screenDx, screenDy, 0);
|
||||
CopyVertex(&triangle[2], v1, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
// ccw winding
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[2], &triangle[1], &triangle[0]);
|
||||
|
||||
CopyVertex(&triangle[1], v0, -screenDx, -screenDy, bpmem.lineptwidth.lineoff);
|
||||
|
||||
Rasterizer::DrawTriangleFrontFace(&triangle[0], &triangle[1], &triangle[2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface)
|
||||
{
|
||||
int mask = CalcClipMask(v0);
|
||||
mask &= CalcClipMask(v1);
|
||||
mask &= CalcClipMask(v2);
|
||||
|
||||
if(mask)
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.numTrianglesRejected)
|
||||
return false;
|
||||
}
|
||||
|
||||
float x0 = v0->projectedPosition.x;
|
||||
float x1 = v1->projectedPosition.x;
|
||||
float x2 = v2->projectedPosition.x;
|
||||
float y1 = v1->projectedPosition.y;
|
||||
float y0 = v0->projectedPosition.y;
|
||||
float y2 = v2->projectedPosition.y;
|
||||
float w0 = v0->projectedPosition.w;
|
||||
float w1 = v1->projectedPosition.w;
|
||||
float w2 = v2->projectedPosition.w;
|
||||
|
||||
float normalZDir = (x0*w2 - x2*w0)*y1 + (x2*y0 - x0*y2)*w1 + (y2*w0 - y0*w2)*x1;
|
||||
|
||||
backface = normalZDir <= 0.0f;
|
||||
|
||||
if ((bpmem.genMode.cullmode & 1) && !backface) // cull frontfacing
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.numTrianglesCulled)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PerspectiveDivide(OutputVertexData *vertex)
|
||||
{
|
||||
Vec4 &projected = vertex->projectedPosition;
|
||||
Vec3 &screen = vertex->screenPosition;
|
||||
|
||||
float wInverse = 1.0f/projected.w;
|
||||
screen.x = projected.x * wInverse * swxfregs.viewport.wd + m_ViewOffset[0];
|
||||
screen.y = projected.y * wInverse * swxfregs.viewport.ht + m_ViewOffset[1];
|
||||
screen.z = projected.z * wInverse * swxfregs.viewport.zRange + swxfregs.viewport.farZ;
|
||||
}
|
||||
|
||||
}
|
32
Source/Core/VideoBackends/Software/Src/Clipper.h
Normal file
32
Source/Core/VideoBackends/Software/Src/Clipper.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _CLIPPER_H_
|
||||
#define _CLIPPER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
|
||||
namespace Clipper
|
||||
{
|
||||
void Init();
|
||||
|
||||
void SetViewOffset();
|
||||
|
||||
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
|
||||
void ProcessLine(OutputVertexData *v0, OutputVertexData *v1);
|
||||
|
||||
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
|
||||
|
||||
void PerspectiveDivide(OutputVertexData *vertex);
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
276
Source/Core/VideoBackends/Software/Src/DebugUtil.cpp
Normal file
276
Source/Core/VideoBackends/Software/Src/DebugUtil.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "DebugUtil.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "TextureSampler.h"
|
||||
#include "SWVideoConfig.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "StringUtil.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
|
||||
u32 skipFrames = 0;
|
||||
bool drawingHwTriangles = false;
|
||||
|
||||
enum { NumObjectBuffers = 40};
|
||||
|
||||
u32 ObjectBuffer[NumObjectBuffers][EFB_WIDTH*EFB_HEIGHT];
|
||||
u32 TempBuffer[NumObjectBuffers];
|
||||
|
||||
bool DrawnToBuffer[NumObjectBuffers];
|
||||
const char* ObjectBufferName[NumObjectBuffers];
|
||||
int BufferBase[NumObjectBuffers];
|
||||
|
||||
void Init()
|
||||
{
|
||||
for (int i = 0; i < NumObjectBuffers; i++)
|
||||
{
|
||||
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
|
||||
DrawnToBuffer[i] = false;
|
||||
ObjectBufferName[i] = 0;
|
||||
BufferBase[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveTexture(const char* filename, u32 texmap, s32 mip)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
|
||||
u32 width = ti0.width + 1;
|
||||
u32 height = ti0.height + 1;
|
||||
|
||||
u8 *data = new u8[width * height * 4];
|
||||
|
||||
GetTextureBGRA(data, texmap, mip, width, height);
|
||||
|
||||
(void)SaveTGA(filename, width, height, data);
|
||||
|
||||
delete []data;
|
||||
}
|
||||
|
||||
void GetTextureBGRA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height)
|
||||
{
|
||||
u8 sample[4];
|
||||
|
||||
for (u32 y = 0; y < height; y++)
|
||||
{
|
||||
for (u32 x = 0; x < width; x++)
|
||||
{
|
||||
TextureSampler::SampleMip(x << 7, y << 7, mip, false, texmap, sample);
|
||||
|
||||
// RGBA to BGRA
|
||||
*(dst++) = sample[2];
|
||||
*(dst++) = sample[1];
|
||||
*(dst++) = sample[0];
|
||||
*(dst++) = sample[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 GetMaxTextureLod(u32 texmap)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
u8 maxLod = texUnit.texMode1[subTexmap].max_lod;
|
||||
u8 mip = maxLod >> 4;
|
||||
u8 fract = maxLod & 0xf;
|
||||
|
||||
if(fract)
|
||||
++mip;
|
||||
|
||||
return (s32)mip;
|
||||
}
|
||||
|
||||
void DumpActiveTextures()
|
||||
{
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_ind%i_map%i_mip%i.tga",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), texmap, mip);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
TwoTevStageOrders &order = bpmem.tevorders[stageNum2];
|
||||
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
|
||||
s32 maxLod = GetMaxTextureLod(texmap);
|
||||
for (s32 mip = 0; mip <= maxLod; ++mip)
|
||||
{
|
||||
SaveTexture(StringFromFormat("%star%i_stage%i_map%i_mip%i.tga",
|
||||
File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
swstats.thisFrame.numDrawnObjects, stageNum, texmap, mip).c_str(), texmap, mip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DumpEfb(const char* filename)
|
||||
{
|
||||
u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
|
||||
u8 *writePtr = data;
|
||||
u8 sample[4];
|
||||
|
||||
for (int y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (int x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
EfbInterface::GetColor(x, y, sample);
|
||||
// ABGR to BGRA
|
||||
*(writePtr++) = sample[1];
|
||||
*(writePtr++) = sample[2];
|
||||
*(writePtr++) = sample[3];
|
||||
*(writePtr++) = sample[0];
|
||||
}
|
||||
}
|
||||
|
||||
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
|
||||
|
||||
delete []data;
|
||||
}
|
||||
|
||||
void DumpDepth(const char* filename)
|
||||
{
|
||||
u8 *data = new u8[EFB_WIDTH * EFB_HEIGHT * 4];
|
||||
u8 *writePtr = data;
|
||||
|
||||
for (int y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (int x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
u32 depth = EfbInterface::GetDepth(x, y);
|
||||
// depth to bgra
|
||||
*(writePtr++) = (depth >> 16) & 0xff;
|
||||
*(writePtr++) = (depth >> 8) & 0xff;
|
||||
*(writePtr++) = depth & 0xff;
|
||||
*(writePtr++) = 255;
|
||||
}
|
||||
}
|
||||
|
||||
(void)SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
|
||||
|
||||
delete []data;
|
||||
}
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH) * 4;
|
||||
u8 *dst = (u8*)&ObjectBuffer[buffer][offset];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void DrawTempBuffer(u8 *color, int buffer)
|
||||
{
|
||||
u8 *dst = (u8*)&TempBuffer[buffer];
|
||||
*(dst++) = color[2];
|
||||
*(dst++) = color[1];
|
||||
*(dst++) = color[0];
|
||||
*(dst++) = color[3];
|
||||
}
|
||||
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name)
|
||||
{
|
||||
int buffer = bufferBase + subBuffer;
|
||||
|
||||
u32 offset = (x + y * EFB_WIDTH);
|
||||
ObjectBuffer[buffer][offset] = TempBuffer[buffer];
|
||||
|
||||
DrawnToBuffer[buffer] = true;
|
||||
ObjectBufferName[buffer] = name;
|
||||
BufferBase[buffer] = bufferBase;
|
||||
}
|
||||
|
||||
void OnObjectBegin()
|
||||
{
|
||||
if (!g_bSkipCurrentFrame)
|
||||
{
|
||||
if (g_SWVideoConfig.bDumpTextures && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd)
|
||||
DumpActiveTextures();
|
||||
|
||||
if (g_SWVideoConfig.bHwRasterizer)
|
||||
{
|
||||
HwRasterizer::BeginTriangles();
|
||||
drawingHwTriangles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnObjectEnd()
|
||||
{
|
||||
if (!g_bSkipCurrentFrame)
|
||||
{
|
||||
if (g_SWVideoConfig.bDumpObjects && swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawStart && swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawEnd)
|
||||
DumpEfb(StringFromFormat("%sobject%i.tga",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
swstats.thisFrame.numDrawnObjects).c_str());
|
||||
|
||||
if (g_SWVideoConfig.bHwRasterizer || drawingHwTriangles)
|
||||
{
|
||||
HwRasterizer::EndTriangles();
|
||||
drawingHwTriangles = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumObjectBuffers; i++)
|
||||
{
|
||||
if (DrawnToBuffer[i])
|
||||
{
|
||||
DrawnToBuffer[i] = false;
|
||||
(void)SaveTGA(StringFromFormat("%sobject%i_%s(%i).tga",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(),
|
||||
swstats.thisFrame.numDrawnObjects, ObjectBufferName[i], i - BufferBase[i]).c_str(),
|
||||
EFB_WIDTH, EFB_HEIGHT, ObjectBuffer[i]);
|
||||
memset(ObjectBuffer[i], 0, sizeof(ObjectBuffer[i]));
|
||||
}
|
||||
}
|
||||
|
||||
swstats.thisFrame.numDrawnObjects++;
|
||||
}
|
||||
}
|
||||
|
||||
void OnFrameEnd()
|
||||
{
|
||||
if (!g_bSkipCurrentFrame)
|
||||
{
|
||||
if (g_SWVideoConfig.bDumpFrames)
|
||||
{
|
||||
DumpEfb(StringFromFormat("%sframe%i_color.tga",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), swstats.frameCount).c_str());
|
||||
DumpDepth(StringFromFormat("%sframe%i_depth.tga",
|
||||
File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), swstats.frameCount).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
27
Source/Core/VideoBackends/Software/Src/DebugUtil.h
Normal file
27
Source/Core/VideoBackends/Software/Src/DebugUtil.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _DEBUGUTIL_H
|
||||
#define _DEBUGUTIL_H
|
||||
|
||||
namespace DebugUtil
|
||||
{
|
||||
void Init();
|
||||
|
||||
void GetTextureBGRA(u8 *dst, u32 texmap, s32 mip, u32 width, u32 height);
|
||||
|
||||
void DumpActiveTextures();
|
||||
|
||||
void OnObjectBegin();
|
||||
void OnObjectEnd();
|
||||
|
||||
void OnFrameEnd();
|
||||
|
||||
void DrawObjectBuffer(s16 x, s16 y, u8 *color, int bufferBase, int subBuffer, const char *name);
|
||||
|
||||
void DrawTempBuffer(u8 *color, int buffer);
|
||||
void CopyTempBuffer(s16 x, s16 y, int bufferBase, int subBuffer, const char *name);
|
||||
}
|
||||
|
||||
#endif
|
99
Source/Core/VideoBackends/Software/Src/EfbCopy.cpp
Normal file
99
Source/Core/VideoBackends/Software/Src/EfbCopy.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "EfbCopy.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "SWRenderer.h"
|
||||
#include "TextureEncoder.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "SWVideoConfig.h"
|
||||
#include "DebugUtil.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "Core.h"
|
||||
|
||||
namespace EfbCopy
|
||||
{
|
||||
void CopyToXfb()
|
||||
{
|
||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
if (!g_SWVideoConfig.bHwRasterizer)
|
||||
{
|
||||
// copy to open gl for rendering
|
||||
EfbInterface::UpdateColorTexture();
|
||||
SWRenderer::DrawTexture(EfbInterface::efbColorTexture, EFB_WIDTH, EFB_HEIGHT);
|
||||
}
|
||||
|
||||
SWRenderer::SwapBuffer();
|
||||
}
|
||||
|
||||
void CopyToRam()
|
||||
{
|
||||
if (!g_SWVideoConfig.bHwRasterizer)
|
||||
{
|
||||
u8 *dest_ptr = Memory::GetPointer(bpmem.copyTexDest << 5);
|
||||
|
||||
TextureEncoder::Encode(dest_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearEfb()
|
||||
{
|
||||
u32 clearColor = (bpmem.clearcolorAR & 0xff) << 24 | bpmem.clearcolorGB << 8 | (bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
|
||||
int left = bpmem.copyTexSrcXY.x;
|
||||
int top = bpmem.copyTexSrcXY.y;
|
||||
int right = left + bpmem.copyTexSrcWH.x;
|
||||
int bottom = top + bpmem.copyTexSrcWH.y;
|
||||
|
||||
for (u16 y = top; y <= bottom; y++)
|
||||
{
|
||||
for (u16 x = left; x <= right; x++)
|
||||
{
|
||||
EfbInterface::SetColor(x, y, (u8*)(&clearColor));
|
||||
EfbInterface::SetDepth(x, y, bpmem.clearZValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyEfb()
|
||||
{
|
||||
if (bpmem.triggerEFBCopy.copy_to_xfb)
|
||||
DebugUtil::OnFrameEnd();
|
||||
|
||||
if (!g_bSkipCurrentFrame)
|
||||
{
|
||||
if (bpmem.triggerEFBCopy.copy_to_xfb)
|
||||
{
|
||||
CopyToXfb();
|
||||
Core::Callback_VideoCopiedToXFB(true);
|
||||
|
||||
swstats.frameCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyToRam();
|
||||
}
|
||||
|
||||
if (bpmem.triggerEFBCopy.clear)
|
||||
{
|
||||
if (g_SWVideoConfig.bHwRasterizer)
|
||||
HwRasterizer::Clear();
|
||||
else
|
||||
ClearEfb();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bpmem.triggerEFBCopy.copy_to_xfb)
|
||||
{
|
||||
// no frame rendered but tell that a frame has finished for frame skip counter
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
Source/Core/VideoBackends/Software/Src/EfbCopy.h
Normal file
19
Source/Core/VideoBackends/Software/Src/EfbCopy.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _EFB_COPY_H_
|
||||
#define _EFB_COPY_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace EfbCopy
|
||||
{
|
||||
// Copy the EFB to RAM as a texture format or XFB
|
||||
// Clear the EFB if needed
|
||||
void CopyEfb();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
549
Source/Core/VideoBackends/Software/Src/EfbInterface.cpp
Normal file
549
Source/Core/VideoBackends/Software/Src/EfbInterface.cpp
Normal file
@ -0,0 +1,549 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "EfbInterface.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "LookUpTables.h"
|
||||
#include "SWPixelEngine.h"
|
||||
|
||||
|
||||
u8 efb[EFB_WIDTH*EFB_HEIGHT*6];
|
||||
|
||||
|
||||
namespace EfbInterface
|
||||
{
|
||||
|
||||
u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4];
|
||||
|
||||
inline u32 GetColorOffset(u16 x, u16 y)
|
||||
{
|
||||
return (x + y * EFB_WIDTH) * 3;
|
||||
}
|
||||
|
||||
inline u32 GetDepthOffset(u16 x, u16 y)
|
||||
{
|
||||
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoArray(efb, EFB_WIDTH*EFB_HEIGHT*6);
|
||||
p.DoArray(efbColorTexture, EFB_WIDTH*EFB_HEIGHT*4);
|
||||
}
|
||||
|
||||
void SetPixelAlphaOnly(u32 offset, u8 a)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
// do nothing
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 a32 = a;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xffffffc0;
|
||||
val |= (a32 >> 2) & 0x0000003f;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColorOnly(u32 offset, u8 *rgb)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src >> 8;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff00003f;
|
||||
val |= (src >> 4) & 0x00000fc0; // blue
|
||||
val |= (src >> 6) & 0x0003f000; // green
|
||||
val |= (src >> 8) & 0x00fc0000; // red
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)rgb;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src >> 8;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelAlphaColor(u32 offset, u8 *color)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src >> 8;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= (src >> 2) & 0x0000003f; // alpha
|
||||
val |= (src >> 4) & 0x00000fc0; // blue
|
||||
val |= (src >> 6) & 0x0003f000; // green
|
||||
val |= (src >> 8) & 0x00fc0000; // red
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)color;
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= src >> 8;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void GetPixelColor(u32 offset, u8 *color)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
u32 *dst = (u32*)color;
|
||||
u32 val = 0xff | ((src & 0x00ffffff) << 8);
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
{
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
color[ALP_C] = Convert6To8(src & 0x3f);
|
||||
color[BLU_C] = Convert6To8((src >> 6) & 0x3f);
|
||||
color[GRN_C] = Convert6To8((src >> 12) & 0x3f);
|
||||
color[RED_C] = Convert6To8((src >> 18) & 0x3f);
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 src = *(u32*)&efb[offset];
|
||||
u32 *dst = (u32*)color;
|
||||
u32 val = 0xff | ((src & 0x00ffffff) << 8);
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelDepth(u32 offset, u32 depth)
|
||||
{
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= depth & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
u32 *dst = (u32*)&efb[offset];
|
||||
u32 val = *dst & 0xff000000;
|
||||
val |= depth & 0x00ffffff;
|
||||
*dst = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetPixelDepth(u32 offset)
|
||||
{
|
||||
u32 depth = 0;
|
||||
|
||||
switch (bpmem.zcontrol.pixel_format)
|
||||
{
|
||||
case PIXELFMT_RGB8_Z24:
|
||||
case PIXELFMT_RGBA6_Z24:
|
||||
case PIXELFMT_Z24:
|
||||
{
|
||||
depth = (*(u32*)&efb[offset]) & 0x00ffffff;
|
||||
}
|
||||
break;
|
||||
case PIXELFMT_RGB565_Z16:
|
||||
{
|
||||
INFO_LOG(VIDEO, "PIXELFMT_RGB565_Z16 is not supported correctly yet");
|
||||
depth = (*(u32*)&efb[offset]) & 0x00ffffff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unsupported pixel format: %i", bpmem.zcontrol.pixel_format);
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
u32 GetSourceFactor(u8 *srcClr, u8 *dstClr, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case 0: // zero
|
||||
return 0;
|
||||
case 1: // one
|
||||
return 0xffffffff;
|
||||
case 2: // dstclr
|
||||
return *(u32*)dstClr;
|
||||
case 3: // invdstclr
|
||||
return 0xffffffff - *(u32*)dstClr;
|
||||
case 4: // srcalpha
|
||||
{
|
||||
u8 alpha = srcClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 5: // invsrcalpha
|
||||
{
|
||||
u8 alpha = 0xff - srcClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 6: // dstalpha
|
||||
{
|
||||
u8 alpha = dstClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 7: // invdstalpha
|
||||
{
|
||||
u8 alpha = 0xff - dstClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 GetDestinationFactor(u8 *srcClr, u8 *dstClr, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case 0: // zero
|
||||
return 0;
|
||||
case 1: // one
|
||||
return 0xffffffff;
|
||||
case 2: // srcclr
|
||||
return *(u32*)srcClr;
|
||||
case 3: // invsrcclr
|
||||
return 0xffffffff - *(u32*)srcClr;
|
||||
case 4: // srcalpha
|
||||
{
|
||||
u8 alpha = srcClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 5: // invsrcalpha
|
||||
{
|
||||
u8 alpha = 0xff - srcClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 6: // dstalpha
|
||||
{
|
||||
u8 alpha = dstClr[ALP_C] & 0xff;
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
case 7: // invdstalpha
|
||||
{
|
||||
u8 alpha = 0xff - dstClr[ALP_C];
|
||||
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlendColor(u8 *srcClr, u8 *dstClr)
|
||||
{
|
||||
u32 srcFactor = GetSourceFactor(srcClr, dstClr, bpmem.blendmode.srcfactor);
|
||||
u32 dstFactor = GetDestinationFactor(srcClr, dstClr, bpmem.blendmode.dstfactor);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// add MSB of factors to make their range 0 -> 256
|
||||
u32 sf = (srcFactor & 0xff);
|
||||
sf += sf >> 7;
|
||||
|
||||
u32 df = (dstFactor & 0xff);
|
||||
df += df >> 7;
|
||||
|
||||
u32 color = (srcClr[i] * sf + dstClr[i] * df) >> 8;
|
||||
dstClr[i] = (color>255)?255:color;
|
||||
|
||||
dstFactor >>= 8;
|
||||
srcFactor >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void LogicBlend(u32 srcClr, u32 &dstClr, int op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case 0: // clear
|
||||
dstClr = 0;
|
||||
break;
|
||||
case 1: // and
|
||||
dstClr = srcClr & dstClr;
|
||||
break;
|
||||
case 2: // revand
|
||||
dstClr = srcClr & (~dstClr);
|
||||
break;
|
||||
case 3: // copy
|
||||
dstClr = srcClr;
|
||||
break;
|
||||
case 4: // invand
|
||||
dstClr = (~srcClr) & dstClr;
|
||||
break;
|
||||
case 5: // noop
|
||||
// Do nothing
|
||||
break;
|
||||
case 6: // xor
|
||||
dstClr = srcClr ^ dstClr;
|
||||
break;
|
||||
case 7: // or
|
||||
dstClr = srcClr | dstClr;
|
||||
break;
|
||||
case 8: // nor
|
||||
dstClr = ~(srcClr | dstClr);
|
||||
break;
|
||||
case 9: // equiv
|
||||
dstClr = ~(srcClr ^ dstClr);
|
||||
break;
|
||||
case 10: // inv
|
||||
dstClr = ~dstClr;
|
||||
break;
|
||||
case 11: // revor
|
||||
dstClr = srcClr | (~dstClr);
|
||||
break;
|
||||
case 12: // invcopy
|
||||
dstClr = ~srcClr;
|
||||
break;
|
||||
case 13: // invor
|
||||
dstClr = (~srcClr) | dstClr;
|
||||
break;
|
||||
case 14: // nand
|
||||
dstClr = ~(srcClr & dstClr);
|
||||
break;
|
||||
case 15: // set
|
||||
dstClr = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SubtractBlend(u8 *srcClr, u8 *dstClr)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int c = (int)dstClr[i] - (int)srcClr[i];
|
||||
dstClr[i] = (c < 0)?0:c;
|
||||
}
|
||||
}
|
||||
|
||||
void BlendTev(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 dstClr;
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
|
||||
u8 *dstClrPtr = (u8*)&dstClr;
|
||||
|
||||
GetPixelColor(offset, dstClrPtr);
|
||||
|
||||
if (bpmem.blendmode.blendenable)
|
||||
{
|
||||
if (bpmem.blendmode.subtract)
|
||||
SubtractBlend(color, dstClrPtr);
|
||||
else
|
||||
BlendColor(color, dstClrPtr);
|
||||
}
|
||||
else if (bpmem.blendmode.logicopenable)
|
||||
{
|
||||
LogicBlend(*((u32*)color), dstClr, bpmem.blendmode.logicmode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dstClrPtr = color;
|
||||
}
|
||||
|
||||
if (bpmem.dstalpha.enable)
|
||||
dstClrPtr[ALP_C] = bpmem.dstalpha.alpha;
|
||||
|
||||
if (bpmem.blendmode.colorupdate)
|
||||
{
|
||||
if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaColor(offset, dstClrPtr);
|
||||
else
|
||||
SetPixelColorOnly(offset, dstClrPtr);
|
||||
}
|
||||
else if (bpmem.blendmode.alphaupdate)
|
||||
{
|
||||
SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]);
|
||||
}
|
||||
|
||||
// branchless bounding box update
|
||||
SWPixelEngine::pereg.boxLeft = SWPixelEngine::pereg.boxLeft>x?x:SWPixelEngine::pereg.boxLeft;
|
||||
SWPixelEngine::pereg.boxRight = SWPixelEngine::pereg.boxRight<x?x:SWPixelEngine::pereg.boxRight;
|
||||
SWPixelEngine::pereg.boxTop = SWPixelEngine::pereg.boxTop>y?y:SWPixelEngine::pereg.boxTop;
|
||||
SWPixelEngine::pereg.boxBottom = SWPixelEngine::pereg.boxBottom<y?y:SWPixelEngine::pereg.boxBottom;
|
||||
}
|
||||
|
||||
void SetColor(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
if (bpmem.blendmode.colorupdate)
|
||||
{
|
||||
if (bpmem.blendmode.alphaupdate)
|
||||
SetPixelAlphaColor(offset, color);
|
||||
else
|
||||
SetPixelColorOnly(offset, color);
|
||||
}
|
||||
else if (bpmem.blendmode.alphaupdate)
|
||||
{
|
||||
SetPixelAlphaOnly(offset, color[ALP_C]);
|
||||
}
|
||||
}
|
||||
|
||||
void SetDepth(u16 x, u16 y, u32 depth)
|
||||
{
|
||||
if (bpmem.zmode.updateenable)
|
||||
SetPixelDepth(GetDepthOffset(x, y), depth);
|
||||
}
|
||||
|
||||
void GetColor(u16 x, u16 y, u8 *color)
|
||||
{
|
||||
u32 offset = GetColorOffset(x, y);
|
||||
GetPixelColor(offset, color);
|
||||
}
|
||||
|
||||
u32 GetDepth(u16 x, u16 y)
|
||||
{
|
||||
u32 offset = GetDepthOffset(x, y);
|
||||
return GetPixelDepth(offset);
|
||||
}
|
||||
|
||||
u8 *GetPixelPointer(u16 x, u16 y, bool depth)
|
||||
{
|
||||
if (depth)
|
||||
return &efb[GetDepthOffset(x, y)];
|
||||
return &efb[GetColorOffset(x, y)];
|
||||
}
|
||||
|
||||
void UpdateColorTexture()
|
||||
{
|
||||
u32 color;
|
||||
u8* colorPtr = (u8*)&color;
|
||||
u32* texturePtr = (u32*)efbColorTexture;
|
||||
u32 textureAddress = 0;
|
||||
u32 efbOffset = 0;
|
||||
|
||||
for (u16 y = 0; y < EFB_HEIGHT; y++)
|
||||
{
|
||||
for (u16 x = 0; x < EFB_WIDTH; x++)
|
||||
{
|
||||
GetPixelColor(efbOffset, colorPtr);
|
||||
efbOffset += 3;
|
||||
texturePtr[textureAddress++] = Common::swap32(color); // ABGR->RGBA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ZCompare(u16 x, u16 y, u32 z)
|
||||
{
|
||||
u32 offset = GetDepthOffset(x, y);
|
||||
u32 depth = GetPixelDepth(offset);
|
||||
|
||||
bool pass;
|
||||
|
||||
switch (bpmem.zmode.func)
|
||||
{
|
||||
case COMPARE_NEVER:
|
||||
pass = false;
|
||||
break;
|
||||
case COMPARE_LESS:
|
||||
pass = z < depth;
|
||||
break;
|
||||
case COMPARE_EQUAL:
|
||||
pass = z == depth;
|
||||
break;
|
||||
case COMPARE_LEQUAL:
|
||||
pass = z <= depth;
|
||||
break;
|
||||
case COMPARE_GREATER:
|
||||
pass = z > depth;
|
||||
break;
|
||||
case COMPARE_NEQUAL:
|
||||
pass = z != depth;
|
||||
break;
|
||||
case COMPARE_GEQUAL:
|
||||
pass = z >= depth;
|
||||
break;
|
||||
case COMPARE_ALWAYS:
|
||||
pass = true;
|
||||
break;
|
||||
default:
|
||||
pass = false;
|
||||
ERROR_LOG(VIDEO, "Bad Z compare mode %i", bpmem.zmode.func);
|
||||
}
|
||||
|
||||
if (pass && bpmem.zmode.updateenable)
|
||||
{
|
||||
SetPixelDepth(offset, z);
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
}
|
40
Source/Core/VideoBackends/Software/Src/EfbInterface.h
Normal file
40
Source/Core/VideoBackends/Software/Src/EfbInterface.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _EFB_INTERFACE_H_
|
||||
#define _EFB_INTERFACE_H_
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
namespace EfbInterface
|
||||
{
|
||||
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
|
||||
|
||||
enum { ALP_C, BLU_C, GRN_C, RED_C };
|
||||
|
||||
// color order is ABGR in order to emulate RGBA on little-endian hardware
|
||||
|
||||
// does full blending of an incoming pixel
|
||||
void BlendTev(u16 x, u16 y, u8 *color);
|
||||
|
||||
// compare z at location x,y
|
||||
// writes it if it passes
|
||||
// returns result of compare.
|
||||
bool ZCompare(u16 x, u16 y, u32 z);
|
||||
|
||||
// sets the color and alpha
|
||||
void SetColor(u16 x, u16 y, u8 *color);
|
||||
void SetDepth(u16 x, u16 y, u32 depth);
|
||||
|
||||
void GetColor(u16 x, u16 y, u8 *color);
|
||||
u32 GetDepth(u16 x, u16 y);
|
||||
|
||||
u8* GetPixelPointer(u16 x, u16 y, bool depth);
|
||||
|
||||
void UpdateColorTexture();
|
||||
extern u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4]; // RGBA format
|
||||
void DoState(PointerWrap &p);
|
||||
}
|
||||
|
||||
#endif
|
369
Source/Core/VideoBackends/Software/Src/HwRasterizer.cpp
Normal file
369
Source/Core/VideoBackends/Software/Src/HwRasterizer.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
||||
#include <VideoCommon.h>
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "DebugUtil.h"
|
||||
|
||||
#define TEMP_SIZE (1024*1024*4)
|
||||
|
||||
namespace HwRasterizer
|
||||
{
|
||||
float efbHalfWidth;
|
||||
float efbHalfHeight;
|
||||
bool hasTexture;
|
||||
|
||||
u8 *temp;
|
||||
|
||||
// Programs
|
||||
static GLuint colProg, texProg, clearProg;
|
||||
|
||||
// Color
|
||||
static GLint col_apos = -1, col_atex = -1;
|
||||
// Tex
|
||||
static GLint tex_apos = -1, tex_atex = -1, tex_utex = -1;
|
||||
// Clear shader
|
||||
static GLint clear_apos = -1, clear_ucol = -1;
|
||||
|
||||
void CreateShaders()
|
||||
{
|
||||
// Color Vertices
|
||||
static const char *fragcolText =
|
||||
"varying " PREC " vec4 TexCoordOut;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = TexCoordOut;\n"
|
||||
"}\n";
|
||||
// Texture Vertices
|
||||
static const char *fragtexText =
|
||||
"varying " PREC " vec4 TexCoordOut;\n"
|
||||
"uniform " TEXTYPE " Texture;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = " TEXFUNC "(Texture, TexCoordOut.xy);\n"
|
||||
"}\n";
|
||||
// Clear shader
|
||||
static const char *fragclearText =
|
||||
"uniform " PREC " vec4 Color;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = Color;\n"
|
||||
"}\n";
|
||||
// Generic passthrough vertice shaders
|
||||
static const char *vertShaderText =
|
||||
"attribute vec4 pos;\n"
|
||||
"attribute vec4 TexCoordIn;\n "
|
||||
"varying vec4 TexCoordOut;\n "
|
||||
"void main() {\n"
|
||||
" gl_Position = pos;\n"
|
||||
" TexCoordOut = TexCoordIn;\n"
|
||||
"}\n";
|
||||
static const char *vertclearText =
|
||||
"attribute vec4 pos;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = pos;\n"
|
||||
"}\n";
|
||||
|
||||
// Color Program
|
||||
colProg = OpenGL_CompileProgram(vertShaderText, fragcolText);
|
||||
|
||||
// Texture Program
|
||||
texProg = OpenGL_CompileProgram(vertShaderText, fragtexText);
|
||||
|
||||
// Clear Program
|
||||
clearProg = OpenGL_CompileProgram(vertclearText, fragclearText);
|
||||
|
||||
// Color attributes
|
||||
col_apos = glGetAttribLocation(colProg, "pos");
|
||||
col_atex = glGetAttribLocation(colProg, "TexCoordIn");
|
||||
// Texture attributes
|
||||
tex_apos = glGetAttribLocation(texProg, "pos");
|
||||
tex_atex = glGetAttribLocation(texProg, "TexCoordIn");
|
||||
tex_utex = glGetUniformLocation(texProg, "Texture");
|
||||
// Clear attributes
|
||||
clear_apos = glGetAttribLocation(clearProg, "pos");
|
||||
clear_ucol = glGetUniformLocation(clearProg, "Color");
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
efbHalfWidth = EFB_WIDTH / 2.0f;
|
||||
efbHalfHeight = 480 / 2.0f;
|
||||
|
||||
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
|
||||
}
|
||||
void Shutdown()
|
||||
{
|
||||
glDeleteProgram(colProg);
|
||||
glDeleteProgram(texProg);
|
||||
glDeleteProgram(clearProg);
|
||||
}
|
||||
void Prepare()
|
||||
{
|
||||
//legacy multitexturing: select texture channel only.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
#ifndef USE_GLES
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glDisable(GL_BLEND);
|
||||
glClearDepth(1.0f);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
#endif
|
||||
// used by hw rasterizer if it enables blending and depth test
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
CreateShaders();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
static float width, height;
|
||||
void LoadTexture()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
u32 imageAddr = texUnit.texImage3[0].image_base;
|
||||
// Texture Rectangle uses pixel coordinates
|
||||
// While GLES uses texture coordinates
|
||||
#ifdef USE_GLES
|
||||
width = texUnit.texImage0[0].width;
|
||||
height = texUnit.texImage0[0].height;
|
||||
#else
|
||||
width = 1;
|
||||
height = 1;
|
||||
#endif
|
||||
TexCacheEntry &cacheEntry = textures[imageAddr];
|
||||
cacheEntry.Update();
|
||||
|
||||
glBindTexture(TEX2D, cacheEntry.texture);
|
||||
glTexParameteri(TEX2D, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(TEX2D, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void BeginTriangles()
|
||||
{
|
||||
// disabling depth test sometimes allows more things to be visible
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
hasTexture = bpmem.tevorders[0].enable0;
|
||||
|
||||
if (hasTexture)
|
||||
LoadTexture();
|
||||
}
|
||||
|
||||
void EndTriangles()
|
||||
{
|
||||
glBindTexture(TEX2D, 0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void DrawColorVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight);
|
||||
float z0 = v0->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight);
|
||||
float z1 = v1->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight);
|
||||
float z2 = v2->screenPosition.z / (float)0x00ffffff;
|
||||
|
||||
float r0 = v0->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g0 = v0->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b0 = v0->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
float r1 = v1->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g1 = v1->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b1 = v1->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
float r2 = v2->color[0][OutputVertexData::RED_C] / 255.0f;
|
||||
float g2 = v2->color[0][OutputVertexData::GRN_C] / 255.0f;
|
||||
float b2 = v2->color[0][OutputVertexData::BLU_C] / 255.0f;
|
||||
|
||||
static const GLfloat verts[3][3] = {
|
||||
{ x0, y0, z0 },
|
||||
{ x1, y1, z1 },
|
||||
{ x2, y2, z2 }
|
||||
};
|
||||
static const GLfloat col[3][4] = {
|
||||
{ r0, g0, b0, 1.0f },
|
||||
{ r1, g1, b1, 1.0f },
|
||||
{ r2, g2, b2, 1.0f }
|
||||
};
|
||||
{
|
||||
glUseProgram(colProg);
|
||||
glEnableVertexAttribArray(col_apos);
|
||||
glEnableVertexAttribArray(col_atex);
|
||||
|
||||
glVertexAttribPointer(col_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glVertexAttribPointer(col_atex, 4, GL_FLOAT, GL_FALSE, 0, col);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableVertexAttribArray(col_atex);
|
||||
glDisableVertexAttribArray(col_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void DrawTextureVertex(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
float x0 = (v0->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y0 = 1.0f - (v0->screenPosition.y / efbHalfHeight);
|
||||
float z0 = v0->screenPosition.z;
|
||||
|
||||
float x1 = (v1->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y1 = 1.0f - (v1->screenPosition.y / efbHalfHeight);
|
||||
float z1 = v1->screenPosition.z;
|
||||
|
||||
float x2 = (v2->screenPosition.x / efbHalfWidth) - 1.0f;
|
||||
float y2 = 1.0f - (v2->screenPosition.y / efbHalfHeight);
|
||||
float z2 = v2->screenPosition.z;
|
||||
|
||||
float s0 = v0->texCoords[0].x / width;
|
||||
float t0 = v0->texCoords[0].y / height;
|
||||
|
||||
float s1 = v1->texCoords[0].x / width;
|
||||
float t1 = v1->texCoords[0].y / height;
|
||||
|
||||
float s2 = v2->texCoords[0].x / width;
|
||||
float t2 = v2->texCoords[0].y / height;
|
||||
|
||||
static const GLfloat verts[3][3] = {
|
||||
{ x0, y0, z0 },
|
||||
{ x1, y1, z1 },
|
||||
{ x2, y2, z2 }
|
||||
};
|
||||
static const GLfloat tex[3][2] = {
|
||||
{ s0, t0 },
|
||||
{ s1, t1 },
|
||||
{ s2, t2 }
|
||||
};
|
||||
{
|
||||
glUseProgram(texProg);
|
||||
glEnableVertexAttribArray(tex_apos);
|
||||
glEnableVertexAttribArray(tex_atex);
|
||||
|
||||
glVertexAttribPointer(tex_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glVertexAttribPointer(tex_atex, 2, GL_FLOAT, GL_FALSE, 0, tex);
|
||||
glUniform1i(tex_utex, 0);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glDisableVertexAttribArray(tex_atex);
|
||||
glDisableVertexAttribArray(tex_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
if (hasTexture)
|
||||
DrawTextureVertex(v0, v1, v2);
|
||||
else
|
||||
DrawColorVertex(v0, v1, v2);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
u8 r = (bpmem.clearcolorAR & 0x00ff);
|
||||
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
|
||||
u8 b = (bpmem.clearcolorGB & 0x00ff);
|
||||
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
|
||||
|
||||
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
|
||||
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
|
||||
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
|
||||
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
|
||||
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
|
||||
static const GLfloat verts[4][3] = {
|
||||
{ left, top, depth },
|
||||
{ right, top, depth },
|
||||
{ right, bottom, depth },
|
||||
{ left, bottom, depth }
|
||||
};
|
||||
{
|
||||
glUseProgram(clearProg);
|
||||
glVertexAttribPointer(clear_apos, 3, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glUniform4f(clear_ucol, r, g, b, a);
|
||||
glEnableVertexAttribArray(col_apos);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glDisableVertexAttribArray(col_apos);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
TexCacheEntry::TexCacheEntry()
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
void TexCacheEntry::Create()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
|
||||
texImage0.hex = texUnit.texImage0[0].hex;
|
||||
texImage1.hex = texUnit.texImage1[0].hex;
|
||||
texImage2.hex = texUnit.texImage2[0].hex;
|
||||
texImage3.hex = texUnit.texImage3[0].hex;
|
||||
texTlut.hex = texUnit.texTlut[0].hex;
|
||||
|
||||
int image_width = texImage0.width;
|
||||
int image_height = texImage0.height;
|
||||
|
||||
DebugUtil::GetTextureBGRA(temp, 0, 0, image_width, image_height);
|
||||
|
||||
glGenTextures(1, (GLuint *)&texture);
|
||||
glBindTexture(TEX2D, texture);
|
||||
#ifdef USE_GLES
|
||||
glTexImage2D(TEX2D, 0, GL_RGBA, (GLsizei)image_width, (GLsizei)image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
|
||||
#else
|
||||
glTexImage2D(TEX2D, 0, GL_RGBA8, (GLsizei)image_width, (GLsizei)image_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
|
||||
#endif
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void TexCacheEntry::Destroy()
|
||||
{
|
||||
if (texture == 0)
|
||||
return;
|
||||
|
||||
glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
void TexCacheEntry::Update()
|
||||
{
|
||||
FourTexUnits &texUnit = bpmem.tex[0];
|
||||
|
||||
// extra checks cause textures to be reloaded much more
|
||||
if (texUnit.texImage0[0].hex != texImage0.hex ||
|
||||
// texUnit.texImage1[0].hex != texImage1.hex ||
|
||||
// texUnit.texImage2[0].hex != texImage2.hex ||
|
||||
texUnit.texImage3[0].hex != texImage3.hex ||
|
||||
texUnit.texTlut[0].hex != texTlut.hex)
|
||||
{
|
||||
Destroy();
|
||||
Create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
Source/Core/VideoBackends/Software/Src/HwRasterizer.h
Normal file
50
Source/Core/VideoBackends/Software/Src/HwRasterizer.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _HW_RASTERIZER_H
|
||||
#define _HW_RASTERIZER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "../../OGL/Src/GLUtil.h"
|
||||
|
||||
struct OutputVertexData;
|
||||
|
||||
namespace HwRasterizer
|
||||
{
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Prepare();
|
||||
|
||||
void BeginTriangles();
|
||||
void EndTriangles();
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
|
||||
void Clear();
|
||||
|
||||
struct TexCacheEntry
|
||||
{
|
||||
TexImage0 texImage0;
|
||||
TexImage1 texImage1;
|
||||
TexImage2 texImage2;
|
||||
TexImage3 texImage3;
|
||||
TexTLUT texTlut;
|
||||
|
||||
GLuint texture;
|
||||
|
||||
TexCacheEntry();
|
||||
|
||||
void Create();
|
||||
void Destroy();
|
||||
void Update();
|
||||
};
|
||||
|
||||
typedef std::map<u32, TexCacheEntry> TextureCache;
|
||||
static TextureCache textures;
|
||||
}
|
||||
|
||||
#endif
|
97
Source/Core/VideoBackends/Software/Src/NativeVertexFormat.h
Normal file
97
Source/Core/VideoBackends/Software/Src/NativeVertexFormat.h
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _NATIVEVERTEXFORMAT_H
|
||||
#define _NATIVEVERTEXFORMAT_H
|
||||
|
||||
#include "Vec3.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define LOADERDECL __cdecl
|
||||
#else
|
||||
#define LOADERDECL
|
||||
#endif
|
||||
|
||||
typedef void (LOADERDECL *TPipelineFunction)();
|
||||
|
||||
struct Vec4
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
|
||||
struct InputVertexData
|
||||
{
|
||||
u8 posMtx;
|
||||
u8 texMtx[8];
|
||||
|
||||
Vec3 position;
|
||||
Vec3 normal[3];
|
||||
u8 color[2][4];
|
||||
float texCoords[8][2];
|
||||
};
|
||||
|
||||
struct OutputVertexData
|
||||
{
|
||||
// components in color channels
|
||||
enum { RED_C, GRN_C, BLU_C, ALP_C };
|
||||
|
||||
Vec3 mvPosition;
|
||||
Vec4 projectedPosition;
|
||||
Vec3 screenPosition;
|
||||
Vec3 normal[3];
|
||||
u8 color[2][4];
|
||||
Vec3 texCoords[8];
|
||||
|
||||
void Lerp(float t, OutputVertexData *a, OutputVertexData *b)
|
||||
{
|
||||
#define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T)
|
||||
|
||||
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
|
||||
|
||||
mvPosition = LINTERP(t, a->mvPosition, b->mvPosition);
|
||||
|
||||
projectedPosition.x = LINTERP(t, a->projectedPosition.x, b->projectedPosition.x);
|
||||
projectedPosition.y = LINTERP(t, a->projectedPosition.y, b->projectedPosition.y);
|
||||
projectedPosition.z = LINTERP(t, a->projectedPosition.z, b->projectedPosition.z);
|
||||
projectedPosition.w = LINTERP(t, a->projectedPosition.w, b->projectedPosition.w);
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
normal[i] = LINTERP(t, a->normal[i], b->normal[i]);
|
||||
}
|
||||
|
||||
u16 t_int = (u16)(t * 256);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]);
|
||||
color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
texCoords[i] = LINTERP(t, a->texCoords[i], b->texCoords[i]);
|
||||
}
|
||||
|
||||
#undef LINTERP
|
||||
#undef LINTERP_INT
|
||||
}
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
mvPosition.DoState(p);
|
||||
p.Do(projectedPosition);
|
||||
screenPosition.DoState(p);
|
||||
for (int i = 0; i < 3;++i)
|
||||
normal[i].DoState(p);
|
||||
p.DoArray(color, sizeof color);
|
||||
for (int i = 0; i < 8;++i)
|
||||
texCoords[i].DoState(p);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
305
Source/Core/VideoBackends/Software/Src/OpcodeDecoder.cpp
Normal file
305
Source/Core/VideoBackends/Software/Src/OpcodeDecoder.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "DataReader.h"
|
||||
|
||||
#include "OpcodeDecoder.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "SWVertexLoader.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "DebugUtil.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "SWVideoConfig.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
typedef void (*DecodingFunction)(u32);
|
||||
|
||||
namespace OpcodeDecoder
|
||||
{
|
||||
static DecodingFunction currentFunction = NULL;
|
||||
static u32 minCommandSize;
|
||||
static u16 streamSize;
|
||||
static u16 streamAddress;
|
||||
static bool readOpcode;
|
||||
static SWVertexLoader vertexLoader;
|
||||
static bool inObjectStream;
|
||||
static u8 lastPrimCmd;
|
||||
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(minCommandSize);
|
||||
// Not sure what is wrong with this. Something(s) in here is causing dolphin to crash/hang when loading states saved from another run of dolphin. Doesn't seem too important anyway...
|
||||
//vertexLoader.DoState(p);
|
||||
p.Do(readOpcode);
|
||||
p.Do(inObjectStream);
|
||||
p.Do(lastPrimCmd);
|
||||
p.Do(streamSize);
|
||||
p.Do(streamAddress);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
ResetDecoding();
|
||||
}
|
||||
|
||||
void DecodePrimitiveStream(u32 iBufferSize)
|
||||
{
|
||||
u32 vertexSize = vertexLoader.GetVertexSize();
|
||||
|
||||
bool skipPrimitives = g_bSkipCurrentFrame ||
|
||||
swstats.thisFrame.numDrawnObjects < g_SWVideoConfig.drawStart ||
|
||||
swstats.thisFrame.numDrawnObjects >= g_SWVideoConfig.drawEnd;
|
||||
|
||||
if (skipPrimitives)
|
||||
{
|
||||
while (streamSize > 0 && iBufferSize >= vertexSize)
|
||||
{
|
||||
g_pVideoData += vertexSize;
|
||||
iBufferSize -= vertexSize;
|
||||
streamSize--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (streamSize > 0 && iBufferSize >= vertexSize)
|
||||
{
|
||||
vertexLoader.LoadVertex();
|
||||
iBufferSize -= vertexSize;
|
||||
streamSize--;
|
||||
}
|
||||
}
|
||||
|
||||
if (streamSize == 0)
|
||||
{
|
||||
// return to normal command processing
|
||||
ResetDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
void ReadXFData(u32 iBufferSize)
|
||||
{
|
||||
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
|
||||
|
||||
u32 pData[16];
|
||||
for (int i = 0; i < streamSize; i++)
|
||||
pData[i] = DataReadU32();
|
||||
SWLoadXFReg(streamSize, streamAddress, pData);
|
||||
|
||||
// return to normal command processing
|
||||
ResetDecoding();
|
||||
}
|
||||
|
||||
void ExecuteDisplayList(u32 addr, u32 count)
|
||||
{
|
||||
u8 *videoDataSave = g_pVideoData;
|
||||
|
||||
u8 *dlStart = Memory::GetPointer(addr);
|
||||
|
||||
g_pVideoData = dlStart;
|
||||
|
||||
while (OpcodeDecoder::CommandRunnable(count))
|
||||
{
|
||||
OpcodeDecoder::Run(count);
|
||||
|
||||
// if data was read by the opcode decoder then the video data pointer changed
|
||||
u32 readCount = (u32)(g_pVideoData - dlStart);
|
||||
dlStart = g_pVideoData;
|
||||
|
||||
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
|
||||
|
||||
count -= readCount;
|
||||
}
|
||||
|
||||
g_pVideoData = videoDataSave;
|
||||
}
|
||||
|
||||
void DecodeStandard(u32 bufferSize)
|
||||
{
|
||||
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
|
||||
|
||||
int Cmd = DataReadU8();
|
||||
|
||||
if (Cmd == GX_NOP)
|
||||
return;
|
||||
// Causes a SIGBUS error on Android
|
||||
// XXX: Investigate
|
||||
#ifndef ANDROID
|
||||
// check if switching in or out of an object
|
||||
// only used for debugging
|
||||
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
|
||||
{
|
||||
inObjectStream = false;
|
||||
DebugUtil::OnObjectEnd();
|
||||
}
|
||||
if (Cmd & 0x80 && !inObjectStream)
|
||||
{
|
||||
inObjectStream = true;
|
||||
lastPrimCmd = Cmd & 0x87;
|
||||
DebugUtil::OnObjectBegin();
|
||||
}
|
||||
#endif
|
||||
switch(Cmd)
|
||||
{
|
||||
case GX_NOP:
|
||||
break;
|
||||
|
||||
case GX_LOAD_CP_REG: //0x08
|
||||
{
|
||||
u32 SubCmd = DataReadU8();
|
||||
u32 Value = DataReadU32();
|
||||
SWLoadCPReg(SubCmd, Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GX_LOAD_XF_REG:
|
||||
{
|
||||
u32 Cmd2 = DataReadU32();
|
||||
streamSize = ((Cmd2 >> 16) & 15) + 1;
|
||||
streamAddress = Cmd2 & 0xFFFF;
|
||||
currentFunction = ReadXFData;
|
||||
minCommandSize = streamSize * 4;
|
||||
readOpcode = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case GX_LOAD_INDX_A: //used for position matrices
|
||||
SWLoadIndexedXF(DataReadU32(), 0xC);
|
||||
break;
|
||||
case GX_LOAD_INDX_B: //used for normal matrices
|
||||
SWLoadIndexedXF(DataReadU32(), 0xD);
|
||||
break;
|
||||
case GX_LOAD_INDX_C: //used for postmatrices
|
||||
SWLoadIndexedXF(DataReadU32(), 0xE);
|
||||
break;
|
||||
case GX_LOAD_INDX_D: //used for lights
|
||||
SWLoadIndexedXF(DataReadU32(), 0xF);
|
||||
break;
|
||||
|
||||
case GX_CMD_CALL_DL:
|
||||
{
|
||||
u32 dwAddr = DataReadU32();
|
||||
u32 dwCount = DataReadU32();
|
||||
ExecuteDisplayList(dwAddr, dwCount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
// zelda 4 swords calls it and checks the metrics registers after that
|
||||
break;
|
||||
|
||||
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
|
||||
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
|
||||
break;
|
||||
|
||||
case GX_LOAD_BP_REG: //0x61
|
||||
{
|
||||
u32 cmd = DataReadU32();
|
||||
SWLoadBPReg(cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
// draw primitives
|
||||
default:
|
||||
if (Cmd & 0x80)
|
||||
{
|
||||
u8 vatIndex = Cmd & GX_VAT_MASK;
|
||||
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
|
||||
vertexLoader.SetFormat(vatIndex, primitiveType);
|
||||
|
||||
// switch to primitive processing
|
||||
streamSize = DataReadU16();
|
||||
currentFunction = DecodePrimitiveStream;
|
||||
minCommandSize = vertexLoader.GetVertexSize();
|
||||
readOpcode = false;
|
||||
|
||||
INCSTAT(swstats.thisFrame.numPrimatives);
|
||||
DEBUG_LOG(VIDEO, "Draw begin");
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Init()
|
||||
{
|
||||
inObjectStream = false;
|
||||
lastPrimCmd = 0;
|
||||
ResetDecoding();
|
||||
}
|
||||
|
||||
void ResetDecoding()
|
||||
{
|
||||
currentFunction = DecodeStandard;
|
||||
minCommandSize = 1;
|
||||
readOpcode = true;
|
||||
}
|
||||
|
||||
bool CommandRunnable(u32 iBufferSize)
|
||||
{
|
||||
if (iBufferSize < minCommandSize)
|
||||
return false;
|
||||
|
||||
if (readOpcode)
|
||||
{
|
||||
u8 Cmd = DataPeek8(0);
|
||||
u32 minSize = 1;
|
||||
|
||||
switch(Cmd)
|
||||
{
|
||||
case GX_LOAD_CP_REG: //0x08
|
||||
minSize = 6;
|
||||
break;
|
||||
|
||||
case GX_LOAD_XF_REG:
|
||||
minSize = 5;
|
||||
break;
|
||||
|
||||
case GX_LOAD_INDX_A: //used for position matrices
|
||||
minSize = 5;
|
||||
break;
|
||||
case GX_LOAD_INDX_B: //used for normal matrices
|
||||
minSize = 5;
|
||||
break;
|
||||
case GX_LOAD_INDX_C: //used for postmatrices
|
||||
minSize = 5;
|
||||
break;
|
||||
case GX_LOAD_INDX_D: //used for lights
|
||||
minSize = 5;
|
||||
break;
|
||||
|
||||
case GX_CMD_CALL_DL:
|
||||
minSize = 9;
|
||||
break;
|
||||
|
||||
case GX_LOAD_BP_REG: //0x61
|
||||
minSize = 5;
|
||||
break;
|
||||
|
||||
// draw primitives
|
||||
default:
|
||||
if (Cmd & 0x80)
|
||||
minSize = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
return (iBufferSize >= minSize);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Run(u32 iBufferSize)
|
||||
{
|
||||
currentFunction(iBufferSize);
|
||||
}
|
||||
|
||||
}
|
51
Source/Core/VideoBackends/Software/Src/OpcodeDecoder.h
Normal file
51
Source/Core/VideoBackends/Software/Src/OpcodeDecoder.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _OPCODEDECODER_H_
|
||||
#define _OPCODEDECODER_H_
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
namespace OpcodeDecoder
|
||||
{
|
||||
|
||||
#define GX_NOP 0x00
|
||||
|
||||
#define GX_LOAD_BP_REG 0x61
|
||||
#define GX_LOAD_CP_REG 0x08
|
||||
#define GX_LOAD_XF_REG 0x10
|
||||
#define GX_LOAD_INDX_A 0x20
|
||||
#define GX_LOAD_INDX_B 0x28
|
||||
#define GX_LOAD_INDX_C 0x30
|
||||
#define GX_LOAD_INDX_D 0x38
|
||||
|
||||
#define GX_CMD_CALL_DL 0x40
|
||||
#define GX_CMD_INVL_VC 0x48
|
||||
|
||||
#define GX_PRIMITIVE_MASK 0x78
|
||||
#define GX_PRIMITIVE_SHIFT 3
|
||||
#define GX_VAT_MASK 0x07
|
||||
|
||||
//these are defined 1/8th of their real values and without their top bit
|
||||
#define GX_DRAW_QUADS 0x0 //0x80
|
||||
#define GX_DRAW_TRIANGLES 0x2 //0x90
|
||||
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
|
||||
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
|
||||
#define GX_DRAW_LINES 0x5 //0xA8
|
||||
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
|
||||
#define GX_DRAW_POINTS 0x7 //0xB8
|
||||
|
||||
void Init();
|
||||
|
||||
void ResetDecoding();
|
||||
|
||||
bool CommandRunnable(u32 iBufferSize);
|
||||
|
||||
void Run(u32 iBufferSize);
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
}
|
||||
|
||||
#endif
|
215
Source/Core/VideoBackends/Software/Src/RasterFont.cpp
Normal file
215
Source/Core/VideoBackends/Software/Src/RasterFont.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "../../OGL/Src/GLUtil.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "RasterFont.h"
|
||||
// globals
|
||||
|
||||
const 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);
|
||||
}
|
||||
}
|
30
Source/Core/VideoBackends/Software/Src/RasterFont.h
Normal file
30
Source/Core/VideoBackends/Software/Src/RasterFont.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _RASTERFONT_H_
|
||||
#define _RASTERFONT_H_
|
||||
|
||||
class RasterFont
|
||||
{
|
||||
public:
|
||||
RasterFont();
|
||||
~RasterFont(void);
|
||||
static int debug;
|
||||
|
||||
// some useful constants
|
||||
enum {char_width = 10};
|
||||
enum {char_height = 15};
|
||||
|
||||
// and the happy helper functions
|
||||
void printString(const char *s, double x, double y, double z=0.0);
|
||||
void printCenteredString(const char *s, double y, int screen_width, double z=0.0);
|
||||
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight);
|
||||
private:
|
||||
int fontOffset;
|
||||
char *temp_buffer;
|
||||
enum {TEMP_BUFFER_SIZE = 64 * 1024};
|
||||
};
|
||||
|
||||
#endif // _RASTERFONT_H_
|
498
Source/Core/VideoBackends/Software/Src/Rasterizer.cpp
Normal file
498
Source/Core/VideoBackends/Software/Src/Rasterizer.cpp
Normal file
@ -0,0 +1,498 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "Rasterizer.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "Tev.h"
|
||||
#include "SWPixelEngine.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "SWVideoConfig.h"
|
||||
|
||||
|
||||
#define BLOCK_SIZE 2
|
||||
|
||||
#define CLAMP(x, a, b) (x>b)?b:(x<a)?a:x
|
||||
|
||||
// returns approximation of log2(f) in s28.4
|
||||
// results are close enough to use for LOD
|
||||
static inline s32 FixedLog2(float f)
|
||||
{
|
||||
u32 *x = (u32*)&f;
|
||||
s32 logInt = ((*x & 0x7F800000) >> 19) - 2032; // integer part
|
||||
s32 logFract = (*x & 0x007fffff) >> 19; // approximate fractional part
|
||||
|
||||
return logInt + logFract;
|
||||
}
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
Slope ZSlope;
|
||||
Slope WSlope;
|
||||
Slope ColorSlopes[2][4];
|
||||
Slope TexSlopes[8][3];
|
||||
|
||||
s32 vertex0X;
|
||||
s32 vertex0Y;
|
||||
float vertexOffsetX;
|
||||
float vertexOffsetY;
|
||||
|
||||
s32 scissorLeft = 0;
|
||||
s32 scissorTop = 0;
|
||||
s32 scissorRight = 0;
|
||||
s32 scissorBottom = 0;
|
||||
|
||||
Tev tev;
|
||||
RasterBlock rasterBlock;
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
ZSlope.DoState(p);
|
||||
WSlope.DoState(p);
|
||||
for (int i=0;i<2;++i)
|
||||
for (int n=0; n<4; ++n)
|
||||
ColorSlopes[i][n].DoState(p);
|
||||
for (int i=0;i<8;++i)
|
||||
for (int n=0; n<3; ++n)
|
||||
TexSlopes[i][n].DoState(p);
|
||||
p.Do(vertex0X);
|
||||
p.Do(vertex0Y);
|
||||
p.Do(vertexOffsetX);
|
||||
p.Do(vertexOffsetY);
|
||||
p.Do(scissorLeft);
|
||||
p.Do(scissorTop);
|
||||
p.Do(scissorRight);
|
||||
p.Do(scissorBottom);
|
||||
tev.DoState(p);
|
||||
p.Do(rasterBlock);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
tev.Init();
|
||||
|
||||
// Set initial z reference plane in the unlikely case that zfreeze is enabled when drawing the first primitive.
|
||||
// TODO: This is just a guess!
|
||||
ZSlope.dfdx = ZSlope.dfdy = 0.f;
|
||||
ZSlope.f0 = 1.f;
|
||||
}
|
||||
|
||||
inline int iround(float x)
|
||||
{
|
||||
int t;
|
||||
|
||||
#if defined(_WIN32) && !defined(_M_X64)
|
||||
__asm
|
||||
{
|
||||
fld x
|
||||
fistp t
|
||||
}
|
||||
#else
|
||||
t = (int)x;
|
||||
if((x - t) >= 0.5)
|
||||
return t + 1;
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void SetScissor()
|
||||
{
|
||||
int xoff = bpmem.scissorOffset.x * 2 - 342;
|
||||
int yoff = bpmem.scissorOffset.y * 2 - 342;
|
||||
|
||||
scissorLeft = bpmem.scissorTL.x - xoff - 342;
|
||||
if (scissorLeft < 0) scissorLeft = 0;
|
||||
|
||||
scissorTop = bpmem.scissorTL.y - yoff - 342;
|
||||
if (scissorTop < 0) scissorTop = 0;
|
||||
|
||||
scissorRight = bpmem.scissorBR.x - xoff - 341;
|
||||
if (scissorRight > EFB_WIDTH) scissorRight = EFB_WIDTH;
|
||||
|
||||
scissorBottom = bpmem.scissorBR.y - yoff - 341;
|
||||
if (scissorBottom > EFB_HEIGHT) scissorBottom = EFB_HEIGHT;
|
||||
}
|
||||
|
||||
void SetTevReg(int reg, int comp, bool konst, s16 color)
|
||||
{
|
||||
tev.SetRegColor(reg, comp, konst, color);
|
||||
}
|
||||
|
||||
inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.rasterizedPixels);
|
||||
|
||||
float dx = vertexOffsetX + (float)(x - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(y - vertex0Y);
|
||||
|
||||
s32 z = (s32)ZSlope.GetValue(dx, dy);
|
||||
if (z < 0 || z > 0x00ffffff)
|
||||
return;
|
||||
|
||||
if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
|
||||
{
|
||||
// TODO: Test if perf regs are incremented even if test is disabled
|
||||
SWPixelEngine::pereg.IncZInputQuadCount(true);
|
||||
if (bpmem.zmode.testenable)
|
||||
{
|
||||
// early z
|
||||
if (!EfbInterface::ZCompare(x, y, z))
|
||||
return;
|
||||
}
|
||||
SWPixelEngine::pereg.IncZOutputQuadCount(true);
|
||||
}
|
||||
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
|
||||
tev.Position[0] = x;
|
||||
tev.Position[1] = y;
|
||||
tev.Position[2] = z;
|
||||
|
||||
// colors
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for(int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
u16 color = (u16)ColorSlopes[i][comp].GetValue(dx, dy);
|
||||
|
||||
// clamp color value to 0
|
||||
u16 mask = ~(color >> 8);
|
||||
|
||||
tev.Color[i][comp] = color & mask;
|
||||
}
|
||||
}
|
||||
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
// multiply by 128 because TEV stores UVs as s17.7
|
||||
tev.Uv[i].s = (s32)(pixel.Uv[i][0] * 128);
|
||||
tev.Uv[i].t = (s32)(pixel.Uv[i][1] * 128);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
tev.IndirectLod[i] = rasterBlock.IndirectLod[i];
|
||||
tev.IndirectLinear[i] = rasterBlock.IndirectLinear[i];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
tev.TextureLod[i] = rasterBlock.TextureLod[i];
|
||||
tev.TextureLinear[i] = rasterBlock.TextureLinear[i];
|
||||
}
|
||||
|
||||
tev.Draw();
|
||||
}
|
||||
|
||||
void InitTriangle(float X1, float Y1, s32 xi, s32 yi)
|
||||
{
|
||||
vertex0X = xi;
|
||||
vertex0Y = yi;
|
||||
|
||||
// adjust a little less than 0.5
|
||||
const float adjust = 0.495f;
|
||||
|
||||
vertexOffsetX = ((float)xi - X1) + adjust;
|
||||
vertexOffsetY = ((float)yi - Y1) + adjust;
|
||||
}
|
||||
|
||||
void InitSlope(Slope *slope, float f1, float f2, float f3, float DX31, float DX12, float DY12, float DY31)
|
||||
{
|
||||
float DF31 = f3 - f1;
|
||||
float DF21 = f2 - f1;
|
||||
float a = DF31 * -DY12 - DF21 * DY31;
|
||||
float b = DX31 * DF21 + DX12 * DF31;
|
||||
float c = -DX12 * DY31 - DX31 * -DY12;
|
||||
slope->dfdx = -a / c;
|
||||
slope->dfdy = -b / c;
|
||||
slope->f0 = f1;
|
||||
}
|
||||
|
||||
inline void CalculateLOD(s32 &lod, bool &linear, u32 texmap, u32 texcoord)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
// LOD calculation requires data from the texture mode for bias, etc.
|
||||
// it does not seem to use the actual texture size
|
||||
TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
TexMode1& tm1 = texUnit.texMode1[subTexmap];
|
||||
|
||||
float sDelta, tDelta;
|
||||
if (tm0.diag_lod)
|
||||
{
|
||||
float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float *uv1 = rasterBlock.Pixel[1][1].Uv[texcoord];
|
||||
|
||||
sDelta = fabsf(uv0[0] - uv1[0]);
|
||||
tDelta = fabsf(uv0[1] - uv1[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float *uv0 = rasterBlock.Pixel[0][0].Uv[texcoord];
|
||||
float *uv1 = rasterBlock.Pixel[1][0].Uv[texcoord];
|
||||
float *uv2 = rasterBlock.Pixel[0][1].Uv[texcoord];
|
||||
|
||||
sDelta = max(fabsf(uv0[0] - uv1[0]), fabsf(uv0[0] - uv2[0]));
|
||||
tDelta = max(fabsf(uv0[1] - uv1[1]), fabsf(uv0[1] - uv2[1]));
|
||||
}
|
||||
|
||||
// get LOD in s28.4
|
||||
lod = FixedLog2(max(sDelta, tDelta));
|
||||
|
||||
// bias is s2.5
|
||||
int bias = tm0.lod_bias;
|
||||
bias >>= 1;
|
||||
lod += bias;
|
||||
|
||||
linear = ((lod > 0 && (tm0.min_filter & 4)) || (lod <= 0 && tm0.mag_filter));
|
||||
|
||||
// order of checks matters
|
||||
// should be:
|
||||
// if lod > max then max
|
||||
// else if lod < min then min
|
||||
lod = CLAMP(lod, (s32)tm1.min_lod, (s32)tm1.max_lod);
|
||||
}
|
||||
|
||||
void BuildBlock(s32 blockX, s32 blockY)
|
||||
{
|
||||
for (s32 yi = 0; yi < BLOCK_SIZE; yi++)
|
||||
{
|
||||
for (s32 xi = 0; xi < BLOCK_SIZE; xi++)
|
||||
{
|
||||
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
|
||||
|
||||
float dx = vertexOffsetX + (float)(xi + blockX - vertex0X);
|
||||
float dy = vertexOffsetY + (float)(yi + blockY - vertex0Y);
|
||||
|
||||
float invW = 1.0f / WSlope.GetValue(dx, dy);
|
||||
pixel.InvW = invW;
|
||||
|
||||
// tex coords
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
float projection = invW;
|
||||
if (swxfregs.texMtxInfo[i].projection)
|
||||
{
|
||||
float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
|
||||
if (q != 0.0f)
|
||||
projection = invW / q;
|
||||
}
|
||||
|
||||
pixel.Uv[i][0] = TexSlopes[i][0].GetValue(dx, dy) * projection;
|
||||
pixel.Uv[i][1] = TexSlopes[i][1].GetValue(dx, dy) * projection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 indref = bpmem.tevindref.hex;
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numindstages; i++)
|
||||
{
|
||||
u32 texmap = indref & 3;
|
||||
indref >>= 3;
|
||||
u32 texcoord = indref & 3;
|
||||
indref >>= 3;
|
||||
|
||||
CalculateLOD(rasterBlock.IndirectLod[i], rasterBlock.IndirectLinear[i], texmap, texcoord);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i <= bpmem.genMode.numtevstages; i++)
|
||||
{
|
||||
int stageOdd = i&1;
|
||||
TwoTevStageOrders &order = bpmem.tevorders[i >> 1];
|
||||
if(order.getEnable(stageOdd))
|
||||
{
|
||||
u32 texmap = order.getTexMap(stageOdd);
|
||||
u32 texcoord = order.getTexCoord(stageOdd);
|
||||
|
||||
CalculateLOD(rasterBlock.TextureLod[i], rasterBlock.TextureLinear[i], texmap, texcoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||
{
|
||||
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
|
||||
|
||||
if (g_SWVideoConfig.bHwRasterizer)
|
||||
{
|
||||
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
|
||||
return;
|
||||
}
|
||||
|
||||
// adapted from http://www.devmaster.net/forums/showthread.php?t=1884
|
||||
|
||||
// 28.4 fixed-pou32 coordinates. rounded to nearest and adjusted to match hardware output
|
||||
// could also take floor and adjust -8
|
||||
const s32 Y1 = iround(16.0f * v0->screenPosition[1]) - 9;
|
||||
const s32 Y2 = iround(16.0f * v1->screenPosition[1]) - 9;
|
||||
const s32 Y3 = iround(16.0f * v2->screenPosition[1]) - 9;
|
||||
|
||||
const s32 X1 = iround(16.0f * v0->screenPosition[0]) - 9;
|
||||
const s32 X2 = iround(16.0f * v1->screenPosition[0]) - 9;
|
||||
const s32 X3 = iround(16.0f * v2->screenPosition[0]) - 9;
|
||||
|
||||
// Deltas
|
||||
const s32 DX12 = X1 - X2;
|
||||
const s32 DX23 = X2 - X3;
|
||||
const s32 DX31 = X3 - X1;
|
||||
|
||||
const s32 DY12 = Y1 - Y2;
|
||||
const s32 DY23 = Y2 - Y3;
|
||||
const s32 DY31 = Y3 - Y1;
|
||||
|
||||
// Fixed-pos32 deltas
|
||||
const s32 FDX12 = DX12 << 4;
|
||||
const s32 FDX23 = DX23 << 4;
|
||||
const s32 FDX31 = DX31 << 4;
|
||||
|
||||
const s32 FDY12 = DY12 << 4;
|
||||
const s32 FDY23 = DY23 << 4;
|
||||
const s32 FDY31 = DY31 << 4;
|
||||
|
||||
// Bounding rectangle
|
||||
s32 minx = (min(min(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 maxx = (max(max(X1, X2), X3) + 0xF) >> 4;
|
||||
s32 miny = (min(min(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
s32 maxy = (max(max(Y1, Y2), Y3) + 0xF) >> 4;
|
||||
|
||||
// scissor
|
||||
minx = max(minx, scissorLeft);
|
||||
maxx = min(maxx, scissorRight);
|
||||
miny = max(miny, scissorTop);
|
||||
maxy = min(maxy, scissorBottom);
|
||||
|
||||
if (minx >= maxx || miny >= maxy)
|
||||
return;
|
||||
|
||||
// Setup slopes
|
||||
float fltx1 = v0->screenPosition.x;
|
||||
float flty1 = v0->screenPosition.y;
|
||||
float fltdx31 = v2->screenPosition.x - fltx1;
|
||||
float fltdx12 = fltx1 - v1->screenPosition.x;
|
||||
float fltdy12 = flty1 - v1->screenPosition.y;
|
||||
float fltdy31 = v2->screenPosition.y - flty1;
|
||||
|
||||
InitTriangle(fltx1, flty1, (X1 + 0xF) >> 4, (Y1 + 0xF) >> 4);
|
||||
|
||||
float w[3] = { 1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w, 1.0f / v2->projectedPosition.w };
|
||||
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
|
||||
if (!bpmem.genMode.zfreeze || !g_SWVideoConfig.bZFreeze)
|
||||
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
|
||||
for(unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
|
||||
{
|
||||
for(int comp = 0; comp < 4; comp++)
|
||||
InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
|
||||
{
|
||||
for(int comp = 0; comp < 3; comp++)
|
||||
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||
}
|
||||
|
||||
// Start in corner of 8x8 block
|
||||
minx &= ~(BLOCK_SIZE - 1);
|
||||
miny &= ~(BLOCK_SIZE - 1);
|
||||
|
||||
// Half-edge constants
|
||||
s32 C1 = DY12 * X1 - DX12 * Y1;
|
||||
s32 C2 = DY23 * X2 - DX23 * Y2;
|
||||
s32 C3 = DY31 * X3 - DX31 * Y3;
|
||||
|
||||
// Correct for fill convention
|
||||
if(DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
|
||||
if(DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
|
||||
if(DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
||||
|
||||
// Loop through blocks
|
||||
for(s32 y = miny; y < maxy; y += BLOCK_SIZE)
|
||||
{
|
||||
for(s32 x = minx; x < maxx; x += BLOCK_SIZE)
|
||||
{
|
||||
// Corners of block
|
||||
s32 x0 = x << 4;
|
||||
s32 x1 = (x + BLOCK_SIZE - 1) << 4;
|
||||
s32 y0 = y << 4;
|
||||
s32 y1 = (y + BLOCK_SIZE - 1) << 4;
|
||||
|
||||
// Evaluate half-space functions
|
||||
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
|
||||
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
|
||||
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
|
||||
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
|
||||
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
|
||||
|
||||
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
|
||||
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
|
||||
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
|
||||
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
|
||||
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
|
||||
|
||||
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
|
||||
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
|
||||
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
|
||||
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
|
||||
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
|
||||
|
||||
// Skip block when outside an edge
|
||||
if(a == 0x0 || b == 0x0 || c == 0x0)
|
||||
continue;
|
||||
|
||||
BuildBlock(x, y);
|
||||
|
||||
// Accept whole block when totally covered
|
||||
if(a == 0xF && b == 0xF && c == 0xF)
|
||||
{
|
||||
for(s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
for(s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Partially covered block
|
||||
{
|
||||
s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
|
||||
s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
|
||||
s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
|
||||
|
||||
for(s32 iy = 0; iy < BLOCK_SIZE; iy++)
|
||||
{
|
||||
s32 CX1 = CY1;
|
||||
s32 CX2 = CY2;
|
||||
s32 CX3 = CY3;
|
||||
|
||||
for(s32 ix = 0; ix < BLOCK_SIZE; ix++)
|
||||
{
|
||||
if(CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||
{
|
||||
Draw(x + ix, y + iy, ix, iy);
|
||||
}
|
||||
|
||||
CX1 -= FDY12;
|
||||
CX2 -= FDY23;
|
||||
CX3 -= FDY31;
|
||||
}
|
||||
|
||||
CY1 += FDX12;
|
||||
CY2 += FDX23;
|
||||
CY3 += FDX31;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
54
Source/Core/VideoBackends/Software/Src/Rasterizer.h
Normal file
54
Source/Core/VideoBackends/Software/Src/Rasterizer.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _RASTERIZER_H_
|
||||
#define _RASTERIZER_H_
|
||||
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
void Init();
|
||||
|
||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
|
||||
|
||||
void SetScissor();
|
||||
|
||||
void SetTevReg(int reg, int comp, bool konst, s16 color);
|
||||
|
||||
struct Slope
|
||||
{
|
||||
float dfdx;
|
||||
float dfdy;
|
||||
float f0;
|
||||
|
||||
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(dfdx);
|
||||
p.Do(dfdy);
|
||||
p.Do(f0);
|
||||
}
|
||||
};
|
||||
|
||||
struct RasterBlockPixel
|
||||
{
|
||||
float InvW;
|
||||
float Uv[8][2];
|
||||
};
|
||||
|
||||
struct RasterBlock
|
||||
{
|
||||
RasterBlockPixel Pixel[2][2];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
};
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
}
|
||||
|
||||
#endif
|
446
Source/Core/VideoBackends/Software/Src/SWCommandProcessor.cpp
Normal file
446
Source/Core/VideoBackends/Software/Src/SWCommandProcessor.cpp
Normal file
@ -0,0 +1,446 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
#include "Thread.h"
|
||||
#include "Atomic.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "Core.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
|
||||
#include "VideoBackend.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "MathUtil.h"
|
||||
#include "OpcodeDecoder.h"
|
||||
|
||||
|
||||
namespace SWCommandProcessor
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
GATHER_PIPE_SIZE = 32,
|
||||
INT_CAUSE_CP = 0x800
|
||||
};
|
||||
|
||||
// STATE_TO_SAVE
|
||||
// variables
|
||||
|
||||
const int commandBufferSize = 1024 * 1024;
|
||||
const int maxCommandBufferWrite = commandBufferSize - GATHER_PIPE_SIZE;
|
||||
u8 commandBuffer[commandBufferSize];
|
||||
u32 readPos;
|
||||
u32 writePos;
|
||||
int et_UpdateInterrupts;
|
||||
volatile bool interruptSet;
|
||||
volatile bool interruptWaiting;
|
||||
|
||||
CPReg cpreg; // shared between gfx and emulator thread
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoPOD(cpreg);
|
||||
p.DoArray(commandBuffer, commandBufferSize);
|
||||
p.Do(readPos);
|
||||
p.Do(writePos);
|
||||
p.Do(et_UpdateInterrupts);
|
||||
p.Do(interruptSet);
|
||||
p.Do(interruptWaiting);
|
||||
|
||||
// Is this right?
|
||||
p.DoArray(g_pVideoData,writePos);
|
||||
}
|
||||
|
||||
// does it matter that there is no synchronization between threads during writes?
|
||||
inline void WriteLow (u32& _reg, u16 lowbits) {_reg = (_reg & 0xFFFF0000) | lowbits;}
|
||||
inline void WriteHigh(u32& _reg, u16 highbits) {_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16);}
|
||||
|
||||
inline u16 ReadLow (u32 _reg) {return (u16)(_reg & 0xFFFF);}
|
||||
inline u16 ReadHigh (u32 _reg) {return (u16)(_reg >> 16);}
|
||||
|
||||
|
||||
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
||||
{
|
||||
UpdateInterrupts(userdata);
|
||||
}
|
||||
|
||||
inline bool AtBreakpoint()
|
||||
{
|
||||
return cpreg.ctrl.BPEnable && (cpreg.readptr == cpreg.breakpt);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
cpreg.status.Hex = 0;
|
||||
cpreg.status.CommandIdle = 1;
|
||||
cpreg.status.ReadIdle = 1;
|
||||
|
||||
cpreg.ctrl.Hex = 0;
|
||||
cpreg.clear.Hex = 0;
|
||||
|
||||
cpreg.bboxleft = 0;
|
||||
cpreg.bboxtop = 0;
|
||||
cpreg.bboxright = 0;
|
||||
cpreg.bboxbottom = 0;
|
||||
|
||||
cpreg.token = 0;
|
||||
|
||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||
|
||||
// internal buffer position
|
||||
readPos = 0;
|
||||
writePos = 0;
|
||||
|
||||
interruptSet = false;
|
||||
interruptWaiting = false;
|
||||
|
||||
g_pVideoData = 0;
|
||||
g_bSkipCurrentFrame = false;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void RunGpu()
|
||||
{
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
|
||||
{
|
||||
// We are going to do FP math on the main thread so have to save the current state
|
||||
FPURoundMode::SaveSIMDState();
|
||||
FPURoundMode::LoadDefaultSIMDState();
|
||||
|
||||
// run the opcode decoder
|
||||
do
|
||||
{
|
||||
RunBuffer();
|
||||
} while (cpreg.ctrl.GPReadEnable && !AtBreakpoint() && cpreg.readptr != cpreg.writeptr);
|
||||
|
||||
FPURoundMode::LoadSIMDState();
|
||||
}
|
||||
}
|
||||
|
||||
void Read16(u16& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
u32 regAddr = (_Address & 0xFFF) >> 1;
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "(r): 0x%08x : 0x%08x", _Address, ((u16*)&cpreg)[regAddr]);
|
||||
|
||||
if (regAddr < 0x20)
|
||||
_rReturnValue = ((u16*)&cpreg)[regAddr];
|
||||
else
|
||||
_rReturnValue = 0;
|
||||
}
|
||||
|
||||
void Write16(const u16 _Value, const u32 _Address)
|
||||
{
|
||||
INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address);
|
||||
|
||||
switch (_Address & 0xFFF)
|
||||
{
|
||||
case STATUS_REGISTER:
|
||||
{
|
||||
ERROR_LOG(COMMANDPROCESSOR,"\t write to STATUS_REGISTER : %04x", _Value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CTRL_REGISTER:
|
||||
{
|
||||
cpreg.ctrl.Hex = _Value;
|
||||
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || BPIntEnable %s | OvF %s | UndF %s"
|
||||
, cpreg.ctrl.GPReadEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.GPLinkEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.BPEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.BreakPointIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoOverflowIntEnable ? "ON" : "OFF"
|
||||
, cpreg.ctrl.FifoUnderflowIntEnable ? "ON" : "OFF"
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLEAR_REGISTER:
|
||||
{
|
||||
UCPClearReg tmpClear(_Value);
|
||||
|
||||
if (tmpClear.ClearFifoOverflow)
|
||||
cpreg.status.OverflowHiWatermark = 0;
|
||||
if (tmpClear.ClearFifoUnderflow)
|
||||
cpreg.status.UnderflowLoWatermark = 0;
|
||||
|
||||
INFO_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x",_Value);
|
||||
}
|
||||
break;
|
||||
|
||||
// Fifo Registers
|
||||
case FIFO_TOKEN_REGISTER:
|
||||
cpreg.token = _Value;
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_TOKEN_REGISTER : %04x", _Value);
|
||||
break;
|
||||
|
||||
case FIFO_BASE_LO:
|
||||
WriteLow ((u32 &)cpreg.fifobase, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_LO. FIFO base is : %08x", cpreg.fifobase);
|
||||
break;
|
||||
case FIFO_BASE_HI:
|
||||
WriteHigh((u32 &)cpreg.fifobase, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_HI. FIFO base is : %08x", cpreg.fifobase);
|
||||
break;
|
||||
case FIFO_END_LO:
|
||||
WriteLow ((u32 &)cpreg.fifoend, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_LO. FIFO end is : %08x", cpreg.fifoend);
|
||||
break;
|
||||
case FIFO_END_HI:
|
||||
WriteHigh((u32 &)cpreg.fifoend, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_HI. FIFO end is : %08x", cpreg.fifoend);
|
||||
break;
|
||||
|
||||
case FIFO_WRITE_POINTER_LO:
|
||||
WriteLow ((u32 &)cpreg.writeptr, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_LO. write ptr is : %08x", cpreg.writeptr);
|
||||
break;
|
||||
case FIFO_WRITE_POINTER_HI:
|
||||
WriteHigh ((u32 &)cpreg.writeptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_HI. write ptr is : %08x", cpreg.writeptr);
|
||||
break;
|
||||
case FIFO_READ_POINTER_LO:
|
||||
WriteLow ((u32 &)cpreg.readptr, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_LO. read ptr is : %08x", cpreg.readptr);
|
||||
break;
|
||||
case FIFO_READ_POINTER_HI:
|
||||
WriteHigh ((u32 &)cpreg.readptr, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI. read ptr is : %08x", cpreg.readptr);
|
||||
break;
|
||||
|
||||
case FIFO_HI_WATERMARK_LO:
|
||||
WriteLow ((u32 &)cpreg.hiwatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_LO. hiwatermark is : %08x", cpreg.hiwatermark);
|
||||
break;
|
||||
case FIFO_HI_WATERMARK_HI:
|
||||
WriteHigh ((u32 &)cpreg.hiwatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_HI. hiwatermark is : %08x", cpreg.hiwatermark);
|
||||
break;
|
||||
case FIFO_LO_WATERMARK_LO:
|
||||
WriteLow ((u32 &)cpreg.lowatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_LO. lowatermark is : %08x", cpreg.lowatermark);
|
||||
break;
|
||||
case FIFO_LO_WATERMARK_HI:
|
||||
WriteHigh ((u32 &)cpreg.lowatermark, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_HI. lowatermark is : %08x", cpreg.lowatermark);
|
||||
break;
|
||||
|
||||
case FIFO_BP_LO:
|
||||
WriteLow ((u32 &)cpreg.breakpt, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_LO. breakpoint is : %08x", cpreg.breakpt);
|
||||
break;
|
||||
case FIFO_BP_HI:
|
||||
WriteHigh ((u32 &)cpreg.breakpt, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_HI. breakpoint is : %08x", cpreg.breakpt);
|
||||
break;
|
||||
|
||||
case FIFO_RW_DISTANCE_LO:
|
||||
WriteLow ((u32 &)cpreg.rwdistance, _Value & 0xFFE0);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_LO. rwdistance is : %08x", cpreg.rwdistance);
|
||||
break;
|
||||
case FIFO_RW_DISTANCE_HI:
|
||||
WriteHigh ((u32 &)cpreg.rwdistance, _Value);
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_HI. rwdistance is : %08x", cpreg.rwdistance);
|
||||
break;
|
||||
}
|
||||
|
||||
RunGpu();
|
||||
}
|
||||
|
||||
void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
{
|
||||
_rReturnValue = 0;
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Read32 from CommandProcessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void Write32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Write32 at CommandProcessor at 0x%08x", _Address);
|
||||
}
|
||||
|
||||
void STACKALIGN GatherPipeBursted()
|
||||
{
|
||||
if (cpreg.ctrl.GPLinkEnable)
|
||||
{
|
||||
DEBUG_LOG(COMMANDPROCESSOR,"\t WGP burst. write thru : %08x", cpreg.writeptr);
|
||||
|
||||
if (cpreg.writeptr == cpreg.fifoend)
|
||||
cpreg.writeptr = cpreg.fifobase;
|
||||
else
|
||||
cpreg.writeptr += GATHER_PIPE_SIZE;
|
||||
|
||||
Common::AtomicAdd(cpreg.rwdistance, GATHER_PIPE_SIZE);
|
||||
}
|
||||
|
||||
RunGpu();
|
||||
}
|
||||
|
||||
void UpdateInterrupts(u64 userdata)
|
||||
{
|
||||
if (userdata)
|
||||
{
|
||||
interruptSet = true;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt set");
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
interruptSet = false;
|
||||
INFO_LOG(COMMANDPROCESSOR,"Interrupt cleared");
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
|
||||
}
|
||||
interruptWaiting = false;
|
||||
}
|
||||
|
||||
void UpdateInterruptsFromVideoBackend(u64 userdata)
|
||||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata);
|
||||
}
|
||||
|
||||
void ReadFifo()
|
||||
{
|
||||
bool canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
|
||||
bool atBreakpoint = AtBreakpoint();
|
||||
|
||||
if (canRead && !atBreakpoint)
|
||||
{
|
||||
// read from fifo
|
||||
u8 *ptr = Memory::GetPointer(cpreg.readptr);
|
||||
int bytesRead = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// copy to buffer
|
||||
memcpy(&commandBuffer[writePos], ptr, GATHER_PIPE_SIZE);
|
||||
writePos += GATHER_PIPE_SIZE;
|
||||
bytesRead += GATHER_PIPE_SIZE;
|
||||
|
||||
if (cpreg.readptr == cpreg.fifoend)
|
||||
{
|
||||
cpreg.readptr = cpreg.fifobase;
|
||||
ptr = Memory::GetPointer(cpreg.readptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpreg.readptr += GATHER_PIPE_SIZE;
|
||||
ptr += GATHER_PIPE_SIZE;
|
||||
}
|
||||
|
||||
canRead = cpreg.readptr != cpreg.writeptr && writePos < (int)maxCommandBufferWrite;
|
||||
atBreakpoint = AtBreakpoint();
|
||||
} while (canRead && !atBreakpoint);
|
||||
|
||||
Common::AtomicAdd(cpreg.rwdistance, -bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
void SetStatus()
|
||||
{
|
||||
// overflow check
|
||||
if (cpreg.rwdistance > cpreg.hiwatermark)
|
||||
cpreg.status.OverflowHiWatermark = 1;
|
||||
|
||||
// underflow check
|
||||
if (cpreg.rwdistance < cpreg.lowatermark)
|
||||
cpreg.status.UnderflowLoWatermark = 1;
|
||||
|
||||
// breakpoint
|
||||
if (cpreg.ctrl.BPEnable)
|
||||
{
|
||||
if (cpreg.breakpt == cpreg.readptr)
|
||||
{
|
||||
if (!cpreg.status.Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %x", cpreg.readptr);
|
||||
cpreg.status.Breakpoint = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpreg.status.Breakpoint)
|
||||
INFO_LOG(COMMANDPROCESSOR, "Cleared breakpoint at %x", cpreg.readptr);
|
||||
cpreg.status.Breakpoint = 0;
|
||||
}
|
||||
|
||||
cpreg.status.ReadIdle = cpreg.readptr == cpreg.writeptr;
|
||||
|
||||
bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BreakPointIntEnable;
|
||||
bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable;
|
||||
bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable;
|
||||
|
||||
bool interrupt = bpInt || ovfInt || undfInt;
|
||||
|
||||
if (interrupt != interruptSet && !interruptWaiting)
|
||||
{
|
||||
u64 userdata = interrupt?1:0;
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
|
||||
{
|
||||
interruptWaiting = true;
|
||||
SWCommandProcessor::UpdateInterruptsFromVideoBackend(userdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
SWCommandProcessor::UpdateInterrupts(userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RunBuffer()
|
||||
{
|
||||
// fifo is read 32 bytes at a time
|
||||
// read fifo data to internal buffer
|
||||
if (cpreg.ctrl.GPReadEnable)
|
||||
ReadFifo();
|
||||
|
||||
SetStatus();
|
||||
|
||||
_dbg_assert_(COMMANDPROCESSOR, writePos >= readPos);
|
||||
|
||||
g_pVideoData = &commandBuffer[readPos];
|
||||
|
||||
u32 availableBytes = writePos - readPos;
|
||||
|
||||
while (OpcodeDecoder::CommandRunnable(availableBytes))
|
||||
{
|
||||
cpreg.status.CommandIdle = 0;
|
||||
|
||||
OpcodeDecoder::Run(availableBytes);
|
||||
|
||||
// if data was read by the opcode decoder then the video data pointer changed
|
||||
readPos = (u32)(g_pVideoData - &commandBuffer[0]);
|
||||
_dbg_assert_(VIDEO, writePos >= readPos);
|
||||
availableBytes = writePos - readPos;
|
||||
}
|
||||
|
||||
cpreg.status.CommandIdle = 1;
|
||||
|
||||
bool ranDecoder = false;
|
||||
|
||||
// move data remaining in the command buffer
|
||||
if (readPos > 0)
|
||||
{
|
||||
memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes);
|
||||
writePos -= readPos;
|
||||
readPos = 0;
|
||||
|
||||
ranDecoder = true;
|
||||
}
|
||||
|
||||
return ranDecoder;
|
||||
}
|
||||
|
||||
void SetRendering(bool enabled)
|
||||
{
|
||||
g_bSkipCurrentFrame = !enabled;
|
||||
}
|
||||
|
||||
} // end of namespace SWCommandProcessor
|
||||
|
145
Source/Core/VideoBackends/Software/Src/SWCommandProcessor.h
Normal file
145
Source/Core/VideoBackends/Software/Src/SWCommandProcessor.h
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _COMMANDPROCESSOR_H_
|
||||
#define _COMMANDPROCESSOR_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
extern volatile bool g_bSkipCurrentFrame;
|
||||
extern u8* g_pVideoData;
|
||||
|
||||
namespace SWCommandProcessor
|
||||
{
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
STATUS_REGISTER = 0x00,
|
||||
CTRL_REGISTER = 0x02,
|
||||
CLEAR_REGISTER = 0x04,
|
||||
FIFO_TOKEN_REGISTER = 0x0E,
|
||||
FIFO_BOUNDING_BOX_LEFT = 0x10,
|
||||
FIFO_BOUNDING_BOX_RIGHT = 0x12,
|
||||
FIFO_BOUNDING_BOX_TOP = 0x14,
|
||||
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
|
||||
FIFO_BASE_LO = 0x20,
|
||||
FIFO_BASE_HI = 0x22,
|
||||
FIFO_END_LO = 0x24,
|
||||
FIFO_END_HI = 0x26,
|
||||
FIFO_HI_WATERMARK_LO = 0x28,
|
||||
FIFO_HI_WATERMARK_HI = 0x2a,
|
||||
FIFO_LO_WATERMARK_LO = 0x2c,
|
||||
FIFO_LO_WATERMARK_HI = 0x2e,
|
||||
FIFO_RW_DISTANCE_LO = 0x30,
|
||||
FIFO_RW_DISTANCE_HI = 0x32,
|
||||
FIFO_WRITE_POINTER_LO = 0x34,
|
||||
FIFO_WRITE_POINTER_HI = 0x36,
|
||||
FIFO_READ_POINTER_LO = 0x38,
|
||||
FIFO_READ_POINTER_HI = 0x3A,
|
||||
FIFO_BP_LO = 0x3C,
|
||||
FIFO_BP_HI = 0x3E
|
||||
};
|
||||
|
||||
// Fifo Status Register
|
||||
union UCPStatusReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 OverflowHiWatermark : 1;
|
||||
u16 UnderflowLoWatermark: 1;
|
||||
u16 ReadIdle : 1; // done reading
|
||||
u16 CommandIdle : 1; // done processing commands
|
||||
u16 Breakpoint : 1;
|
||||
u16 : 11;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPStatusReg() {Hex = 0; }
|
||||
UCPStatusReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// Fifo Control Register
|
||||
union UCPCtrlReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 GPReadEnable : 1;
|
||||
u16 BPEnable : 1;
|
||||
u16 FifoOverflowIntEnable : 1;
|
||||
u16 FifoUnderflowIntEnable : 1;
|
||||
u16 GPLinkEnable : 1;
|
||||
u16 BreakPointIntEnable : 1;
|
||||
u16 : 10;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPCtrlReg() {Hex = 0; }
|
||||
UCPCtrlReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
// Fifo Control Register
|
||||
union UCPClearReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 ClearFifoOverflow : 1;
|
||||
u16 ClearFifoUnderflow : 1;
|
||||
u16 ClearMetrices : 1;
|
||||
u16 : 13;
|
||||
};
|
||||
u16 Hex;
|
||||
UCPClearReg() {Hex = 0; }
|
||||
UCPClearReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
struct CPReg
|
||||
{
|
||||
UCPStatusReg status; // 0x00
|
||||
UCPCtrlReg ctrl; // 0x02
|
||||
UCPClearReg clear; // 0x04
|
||||
u32 unk0; // 0x06
|
||||
u32 unk1; // 0x0a
|
||||
u16 token; // 0x0e
|
||||
u16 bboxleft; // 0x10
|
||||
u16 bboxtop; // 0x12
|
||||
u16 bboxright; // 0x14
|
||||
u16 bboxbottom; // 0x16
|
||||
u16 unk2; // 0x18
|
||||
u32 fifobase; // 0x20
|
||||
u32 fifoend; // 0x24
|
||||
u32 hiwatermark; // 0x28
|
||||
u32 lowatermark; // 0x2c
|
||||
u32 rwdistance; // 0x30
|
||||
u32 writeptr; // 0x34
|
||||
u32 readptr; // 0x38
|
||||
u32 breakpt; // 0x3c
|
||||
};
|
||||
|
||||
extern CPReg cpreg;
|
||||
|
||||
// Init
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
bool RunBuffer();
|
||||
void RunGpu();
|
||||
|
||||
// Read
|
||||
void Read16(u16& _rReturnValue, const u32 _Address);
|
||||
void Write16(const u16 _Data, const u32 _Address);
|
||||
void Read32(u32& _rReturnValue, const u32 _Address);
|
||||
void Write32(const u32 _Data, const u32 _Address);
|
||||
|
||||
// for CGPFIFO
|
||||
void GatherPipeBursted();
|
||||
void UpdateInterrupts(u64 userdata);
|
||||
void UpdateInterruptsFromVideoBackend(u64 userdata);
|
||||
|
||||
void SetRendering(bool enabled);
|
||||
|
||||
} // end of namespace SWCommandProcessor
|
||||
|
||||
|
||||
#endif
|
162
Source/Core/VideoBackends/Software/Src/SWPixelEngine.cpp
Normal file
162
Source/Core/VideoBackends/Software/Src/SWPixelEngine.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
// http://developer.nvidia.com/object/General_FAQ.html#t6 !!!!!
|
||||
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "CoreTiming.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
|
||||
#include "SWPixelEngine.h"
|
||||
#include "SWCommandProcessor.h"
|
||||
|
||||
|
||||
namespace SWPixelEngine
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
|
||||
INT_CAUSE_PE_FINISH = 0x400, // GP Finished
|
||||
};
|
||||
|
||||
// STATE_TO_SAVE
|
||||
PEReg pereg;
|
||||
|
||||
static bool g_bSignalTokenInterrupt;
|
||||
static bool g_bSignalFinishInterrupt;
|
||||
|
||||
static int et_SetTokenOnMainThread;
|
||||
static int et_SetFinishOnMainThread;
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoPOD(pereg);
|
||||
p.Do(g_bSignalTokenInterrupt);
|
||||
p.Do(g_bSignalFinishInterrupt);
|
||||
p.Do(et_SetTokenOnMainThread);
|
||||
p.Do(et_SetFinishOnMainThread);
|
||||
}
|
||||
|
||||
void UpdateInterrupts();
|
||||
|
||||
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
|
||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
|
||||
|
||||
void Init()
|
||||
{
|
||||
memset(&pereg, 0, sizeof(pereg));
|
||||
|
||||
et_SetTokenOnMainThread = false;
|
||||
g_bSignalFinishInterrupt = false;
|
||||
|
||||
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
||||
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
||||
}
|
||||
|
||||
void Read16(u16& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
DEBUG_LOG(PIXELENGINE, "(r16): 0x%08x", _iAddress);
|
||||
|
||||
u16 address = _iAddress & 0xFFF;
|
||||
|
||||
if (address <= 0x2e)
|
||||
_uReturnValue = ((u16*)&pereg)[address >> 1];
|
||||
}
|
||||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
{
|
||||
WARN_LOG(PIXELENGINE, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
|
||||
}
|
||||
|
||||
void Write16(const u16 _iValue, const u32 _iAddress)
|
||||
{
|
||||
u16 address = _iAddress & 0xFFF;
|
||||
|
||||
switch (address)
|
||||
{
|
||||
case PE_CTRL_REGISTER:
|
||||
{
|
||||
UPECtrlReg tmpCtrl(_iValue);
|
||||
|
||||
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
|
||||
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
|
||||
|
||||
pereg.ctrl.PETokenEnable = tmpCtrl.PETokenEnable;
|
||||
pereg.ctrl.PEFinishEnable = tmpCtrl.PEFinishEnable;
|
||||
pereg.ctrl.PEToken = 0; // this flag is write only
|
||||
pereg.ctrl.PEFinish = 0; // this flag is write only
|
||||
|
||||
DEBUG_LOG(PIXELENGINE, "(w16): PE_CTRL_REGISTER: 0x%04x", _iValue);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (address <= 0x2e)
|
||||
((u16*)&pereg)[address >> 1] = _iValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool AllowIdleSkipping()
|
||||
{
|
||||
return !SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread || (!pereg.ctrl.PETokenEnable && !pereg.ctrl.PEFinishEnable);
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
// check if there is a token-interrupt
|
||||
if (g_bSignalTokenInterrupt & pereg.ctrl.PETokenEnable)
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, true);
|
||||
else
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, false);
|
||||
|
||||
// check if there is a finish-interrupt
|
||||
if (g_bSignalFinishInterrupt & pereg.ctrl.PEFinishEnable)
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, true);
|
||||
else
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, false);
|
||||
}
|
||||
|
||||
|
||||
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
|
||||
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
|
||||
{
|
||||
g_bSignalTokenInterrupt = true;
|
||||
INFO_LOG(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", pereg.token);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
|
||||
{
|
||||
g_bSignalFinishInterrupt = true;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
// SetToken
|
||||
// THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
|
||||
{
|
||||
pereg.token = _token;
|
||||
if (_bSetTokenAcknowledge) // set token INT
|
||||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetTokenOnMainThread,
|
||||
_token | (_bSetTokenAcknowledge << 16));
|
||||
}
|
||||
}
|
||||
|
||||
// SetFinish
|
||||
// THIS IS EXECUTED FROM VIDEO THREAD
|
||||
void SetFinish()
|
||||
{
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_SetFinishOnMainThread, 0);
|
||||
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
|
||||
}
|
||||
|
||||
} // end of namespace SWPixelEngine
|
218
Source/Core/VideoBackends/Software/Src/SWPixelEngine.h
Normal file
218
Source/Core/VideoBackends/Software/Src/SWPixelEngine.h
Normal file
@ -0,0 +1,218 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _PIXELENGINE_H
|
||||
#define _PIXELENGINE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "VideoCommon.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
namespace SWPixelEngine
|
||||
{
|
||||
// internal hardware addresses
|
||||
enum
|
||||
{
|
||||
PE_ZCONF = 0x000, // Z Config
|
||||
PE_ALPHACONF = 0x002, // Alpha Config
|
||||
PE_DSTALPHACONF = 0x004, // Destination Alpha Config
|
||||
PE_ALPHAMODE = 0x006, // Alpha Mode Config
|
||||
PE_ALPHAREAD = 0x008, // Alpha Read
|
||||
PE_CTRL_REGISTER = 0x00a, // Control
|
||||
PE_TOKEN_REG = 0x00e, // Token
|
||||
PE_BBOX_LEFT = 0x010, // Flip Left
|
||||
PE_BBOX_RIGHT = 0x012, // Flip Right
|
||||
PE_BBOX_TOP = 0x014, // Flip Top
|
||||
PE_BBOX_BOTTOM = 0x016, // Flip Bottom
|
||||
|
||||
// NOTE: Order not verified
|
||||
// These indicate the number of quads that are being used as input/output for each particular stage
|
||||
PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L = 0x18,
|
||||
PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H = 0x1a,
|
||||
PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L = 0x1c,
|
||||
PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H = 0x1e,
|
||||
PE_PERF_ZCOMP_INPUT_L = 0x20,
|
||||
PE_PERF_ZCOMP_INPUT_H = 0x22,
|
||||
PE_PERF_ZCOMP_OUTPUT_L = 0x24,
|
||||
PE_PERF_ZCOMP_OUTPUT_H = 0x26,
|
||||
PE_PERF_BLEND_INPUT_L = 0x28,
|
||||
PE_PERF_BLEND_INPUT_H = 0x2a,
|
||||
PE_PERF_EFB_COPY_CLOCKS_L = 0x2c,
|
||||
PE_PERF_EFB_COPY_CLOCKS_H = 0x2e,
|
||||
};
|
||||
|
||||
union UPEZConfReg
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
u16 ZCompEnable : 1; // Z Comparator Enable
|
||||
u16 Function : 3;
|
||||
u16 ZUpdEnable : 1;
|
||||
u16 : 11;
|
||||
};
|
||||
};
|
||||
|
||||
union UPEAlphaConfReg
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT
|
||||
u16 BMLogic : 1; // GX_BM_LOGIC
|
||||
u16 Dither : 1;
|
||||
u16 ColorUpdEnable : 1;
|
||||
u16 AlphaUpdEnable : 1;
|
||||
u16 DstFactor : 3;
|
||||
u16 SrcFactor : 3;
|
||||
u16 Substract : 1; // Additive mode by default
|
||||
u16 BlendOperator : 4;
|
||||
};
|
||||
};
|
||||
|
||||
union UPEDstAlphaConfReg
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
u16 DstAlpha : 8;
|
||||
u16 Enable : 1;
|
||||
u16 : 7;
|
||||
};
|
||||
};
|
||||
|
||||
union UPEAlphaModeConfReg
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
u16 Threshold : 8;
|
||||
u16 CompareMode : 8;
|
||||
};
|
||||
};
|
||||
|
||||
union UPEAlphaReadReg
|
||||
{
|
||||
u16 Hex;
|
||||
struct
|
||||
{
|
||||
u16 ReadMode : 3;
|
||||
u16 : 13;
|
||||
};
|
||||
};
|
||||
|
||||
union UPECtrlReg
|
||||
{
|
||||
struct
|
||||
{
|
||||
u16 PETokenEnable : 1;
|
||||
u16 PEFinishEnable : 1;
|
||||
u16 PEToken : 1; // write only
|
||||
u16 PEFinish : 1; // write only
|
||||
u16 : 12;
|
||||
};
|
||||
u16 Hex;
|
||||
UPECtrlReg() {Hex = 0; }
|
||||
UPECtrlReg(u16 _hex) {Hex = _hex; }
|
||||
};
|
||||
|
||||
struct PEReg
|
||||
{
|
||||
UPEZConfReg zconf;
|
||||
UPEAlphaConfReg alphaConf;
|
||||
UPEDstAlphaConfReg dstAlpha;
|
||||
UPEAlphaModeConfReg alphaMode;
|
||||
UPEAlphaReadReg alphaRead;
|
||||
UPECtrlReg ctrl;
|
||||
u16 unk0;
|
||||
u16 token;
|
||||
|
||||
u16 boxLeft;
|
||||
u16 boxRight;
|
||||
u16 boxTop;
|
||||
u16 boxBottom;
|
||||
|
||||
u16 perfZcompInputZcomplocLo;
|
||||
u16 perfZcompInputZcomplocHi;
|
||||
u16 perfZcompOutputZcomplocLo;
|
||||
u16 perfZcompOutputZcomplocHi;
|
||||
u16 perfZcompInputLo;
|
||||
u16 perfZcompInputHi;
|
||||
u16 perfZcompOutputLo;
|
||||
u16 perfZcompOutputHi;
|
||||
u16 perfBlendInputLo;
|
||||
u16 perfBlendInputHi;
|
||||
u16 perfEfbCopyClocksLo;
|
||||
u16 perfEfbCopyClocksHi;
|
||||
|
||||
// NOTE: hardware doesn't process individual pixels but quads instead. Current software renderer architecture works on pixels though, so we have this "quad" hack here to only increment the registers on every fourth rendered pixel
|
||||
void IncZInputQuadCount(bool early_ztest)
|
||||
{
|
||||
static int quad = 0;
|
||||
if (++quad != 3)
|
||||
return;
|
||||
quad = 0;
|
||||
|
||||
if (early_ztest)
|
||||
{
|
||||
if (++perfZcompInputZcomplocLo == 0)
|
||||
perfZcompInputZcomplocHi++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++perfZcompInputLo == 0)
|
||||
perfZcompInputHi++;
|
||||
}
|
||||
}
|
||||
void IncZOutputQuadCount(bool early_ztest)
|
||||
{
|
||||
static int quad = 0;
|
||||
if (++quad != 3)
|
||||
return;
|
||||
quad = 0;
|
||||
|
||||
if (early_ztest)
|
||||
{
|
||||
if (++perfZcompOutputZcomplocLo == 0)
|
||||
perfZcompOutputZcomplocHi++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++perfZcompOutputLo == 0)
|
||||
perfZcompOutputHi++;
|
||||
}
|
||||
}
|
||||
void IncBlendInputQuadCount()
|
||||
{
|
||||
static int quad = 0;
|
||||
if (++quad != 3)
|
||||
return;
|
||||
quad = 0;
|
||||
|
||||
if (++perfBlendInputLo == 0)
|
||||
perfBlendInputHi++;
|
||||
}
|
||||
};
|
||||
|
||||
extern PEReg pereg;
|
||||
|
||||
void Init();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
// Read
|
||||
void Read16(u16& _uReturnValue, const u32 _iAddress);
|
||||
|
||||
// Write
|
||||
void Write16(const u16 _iValue, const u32 _iAddress);
|
||||
void Write32(const u32 _iValue, const u32 _iAddress);
|
||||
|
||||
// gfx backend support
|
||||
void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
|
||||
void SetFinish(void);
|
||||
bool AllowIdleSkipping();
|
||||
|
||||
} // end of namespace SWPixelEngine
|
||||
|
||||
#endif
|
185
Source/Core/VideoBackends/Software/Src/SWRenderer.cpp
Normal file
185
Source/Core/VideoBackends/Software/Src/SWRenderer.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "../../OGL/Src/GLUtil.h"
|
||||
#include "RasterFont.h"
|
||||
#include "SWRenderer.h"
|
||||
#include "SWStatistics.h"
|
||||
|
||||
#include "OnScreenDisplay.h"
|
||||
|
||||
static GLuint s_RenderTarget = 0;
|
||||
|
||||
static GLint attr_pos = -1, attr_tex = -1;
|
||||
static GLint uni_tex = -1;
|
||||
static GLuint program;
|
||||
|
||||
// Rasterfont isn't compatible with GLES
|
||||
// degasus: I think it does, but I can't test it
|
||||
#ifndef USE_GLES
|
||||
RasterFont* s_pfont = NULL;
|
||||
#endif
|
||||
|
||||
void SWRenderer::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void SWRenderer::Shutdown()
|
||||
{
|
||||
glDeleteProgram(program);
|
||||
glDeleteTextures(1, &s_RenderTarget);
|
||||
#ifndef USE_GLES
|
||||
delete s_pfont;
|
||||
s_pfont = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CreateShaders()
|
||||
{
|
||||
static const char *fragShaderText =
|
||||
"varying " PREC " vec2 TexCoordOut;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"void main() {\n"
|
||||
" " PREC " vec4 tmpcolor;\n"
|
||||
" tmpcolor = texture2D(Texture, TexCoordOut);\n"
|
||||
" gl_FragColor = tmpcolor;\n"
|
||||
"}\n";
|
||||
static const char *vertShaderText =
|
||||
"attribute vec4 pos;\n"
|
||||
"attribute vec2 TexCoordIn;\n "
|
||||
"varying vec2 TexCoordOut;\n "
|
||||
"void main() {\n"
|
||||
" gl_Position = pos;\n"
|
||||
" TexCoordOut = TexCoordIn;\n"
|
||||
"}\n";
|
||||
|
||||
program = OpenGL_CompileProgram(vertShaderText, fragShaderText);
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
uni_tex = glGetUniformLocation(program, "Texture");
|
||||
attr_pos = glGetAttribLocation(program, "pos");
|
||||
attr_tex = glGetAttribLocation(program, "TexCoordIn");
|
||||
}
|
||||
|
||||
void SWRenderer::Prepare()
|
||||
{
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
glGenTextures(1, &s_RenderTarget);
|
||||
|
||||
CreateShaders();
|
||||
// TODO: Enable for GLES once RasterFont supports GLES
|
||||
#ifndef USE_GLES
|
||||
s_pfont = new RasterFont();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
#endif
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void SWRenderer::RenderText(const char* pstr, int left, int top, u32 color)
|
||||
{
|
||||
#ifndef USE_GLES
|
||||
int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
|
||||
int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
|
||||
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
|
||||
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
|
||||
s_pfont->printMultilineText(pstr,
|
||||
left * 2.0f / (float)nBackbufferWidth - 1,
|
||||
1 - top * 2.0f / (float)nBackbufferHeight,
|
||||
0, nBackbufferWidth, nBackbufferHeight);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SWRenderer::DrawDebugText()
|
||||
{
|
||||
char debugtext_buffer[8192];
|
||||
char *p = debugtext_buffer;
|
||||
p[0] = 0;
|
||||
|
||||
if (g_SWVideoConfig.bShowStats)
|
||||
{
|
||||
p+=sprintf(p,"Objects: %i\n",swstats.thisFrame.numDrawnObjects);
|
||||
p+=sprintf(p,"Primitives: %i\n",swstats.thisFrame.numPrimatives);
|
||||
p+=sprintf(p,"Vertices Loaded: %i\n",swstats.thisFrame.numVerticesLoaded);
|
||||
|
||||
p+=sprintf(p,"Triangles Input: %i\n",swstats.thisFrame.numTrianglesIn);
|
||||
p+=sprintf(p,"Triangles Rejected: %i\n",swstats.thisFrame.numTrianglesRejected);
|
||||
p+=sprintf(p,"Triangles Culled: %i\n",swstats.thisFrame.numTrianglesCulled);
|
||||
p+=sprintf(p,"Triangles Clipped: %i\n",swstats.thisFrame.numTrianglesClipped);
|
||||
p+=sprintf(p,"Triangles Drawn: %i\n",swstats.thisFrame.numTrianglesDrawn);
|
||||
|
||||
p+=sprintf(p,"Rasterized Pix: %i\n",swstats.thisFrame.rasterizedPixels);
|
||||
p+=sprintf(p,"TEV Pix In: %i\n",swstats.thisFrame.tevPixelsIn);
|
||||
p+=sprintf(p,"TEV Pix Out: %i\n",swstats.thisFrame.tevPixelsOut);
|
||||
}
|
||||
|
||||
// Render a shadow, and then the text.
|
||||
SWRenderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
|
||||
SWRenderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
void SWRenderer::DrawTexture(u8 *texture, int width, int height)
|
||||
{
|
||||
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
|
||||
|
||||
// Update GLViewPort
|
||||
glViewport(0, 0, glWidth, glHeight);
|
||||
glScissor(0, 0, glWidth, glHeight);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, s_RenderTarget);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glUseProgram(program);
|
||||
static const GLfloat verts[4][2] = {
|
||||
{ -1, -1}, // Left top
|
||||
{ -1, 1}, // left bottom
|
||||
{ 1, 1}, // right bottom
|
||||
{ 1, -1} // right top
|
||||
};
|
||||
static const GLfloat texverts[4][2] = {
|
||||
{0, 1},
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{1, 1}
|
||||
};
|
||||
|
||||
glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
|
||||
glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, texverts);
|
||||
glEnableVertexAttribArray(attr_pos);
|
||||
glEnableVertexAttribArray(attr_tex);
|
||||
glUniform1i(uni_tex, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
glDisableVertexAttribArray(attr_pos);
|
||||
glDisableVertexAttribArray(attr_tex);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void SWRenderer::SwapBuffer()
|
||||
{
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::OSD_ONFRAME);
|
||||
|
||||
DrawDebugText();
|
||||
|
||||
glFlush();
|
||||
|
||||
GLInterface->Swap();
|
||||
|
||||
swstats.ResetFrame();
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
24
Source/Core/VideoBackends/Software/Src/SWRenderer.h
Normal file
24
Source/Core/VideoBackends/Software/Src/SWRenderer.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _RENDERER_H_
|
||||
#define _RENDERER_H_
|
||||
|
||||
#include "CommonTypes.h"
|
||||
|
||||
namespace SWRenderer
|
||||
{
|
||||
void Init();
|
||||
void Prepare();
|
||||
void Shutdown();
|
||||
|
||||
void RenderText(const char* pstr, int left, int top, u32 color);
|
||||
void DrawDebugText();
|
||||
|
||||
void DrawTexture(u8 *texture, int width, int height);
|
||||
|
||||
void SwapBuffer();
|
||||
}
|
||||
|
||||
#endif
|
25
Source/Core/VideoBackends/Software/Src/SWStatistics.cpp
Normal file
25
Source/Core/VideoBackends/Software/Src/SWStatistics.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "SWStatistics.h"
|
||||
|
||||
SWStatistics swstats;
|
||||
|
||||
template <class T>
|
||||
void Xchg(T& a, T&b)
|
||||
{
|
||||
T c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
SWStatistics::SWStatistics()
|
||||
{
|
||||
frameCount = 0;
|
||||
}
|
||||
|
||||
void SWStatistics::ResetFrame()
|
||||
{
|
||||
memset(&thisFrame, 0, sizeof(ThisFrame));
|
||||
}
|
50
Source/Core/VideoBackends/Software/Src/SWStatistics.h
Normal file
50
Source/Core/VideoBackends/Software/Src/SWStatistics.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "CommonTypes.h"
|
||||
#include "SWVideoConfig.h"
|
||||
|
||||
#ifndef _STATISTICS_H
|
||||
#define _STATISTICS_H
|
||||
|
||||
struct SWStatistics
|
||||
{
|
||||
struct ThisFrame
|
||||
{
|
||||
u32 numDrawnObjects;
|
||||
u32 numPrimatives;
|
||||
u32 numVerticesLoaded;
|
||||
u32 numVerticesOut;
|
||||
|
||||
u32 numTrianglesIn;
|
||||
u32 numTrianglesRejected;
|
||||
u32 numTrianglesCulled;
|
||||
u32 numTrianglesClipped;
|
||||
u32 numTrianglesDrawn;
|
||||
|
||||
u32 rasterizedPixels;
|
||||
u32 tevPixelsIn;
|
||||
u32 tevPixelsOut;
|
||||
};
|
||||
|
||||
u32 frameCount;
|
||||
SWStatistics();
|
||||
|
||||
ThisFrame thisFrame;
|
||||
void ResetFrame();
|
||||
};
|
||||
|
||||
extern SWStatistics swstats;
|
||||
|
||||
#if (STATISTICS)
|
||||
#define INCSTAT(a) (a)++;
|
||||
#define ADDSTAT(a,b) (a)+=(b);
|
||||
#define SETSTAT(a,x) (a)=(int)(x);
|
||||
#else
|
||||
#define INCSTAT(a) ;
|
||||
#define ADDSTAT(a,b) ;
|
||||
#define SETSTAT(a,x) ;
|
||||
#endif
|
||||
|
||||
#endif // _STATISTICS_H
|
334
Source/Core/VideoBackends/Software/Src/SWVertexLoader.cpp
Normal file
334
Source/Core/VideoBackends/Software/Src/SWVertexLoader.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "SWVertexLoader.h"
|
||||
#include "VertexLoader_Position.h"
|
||||
#include "VertexLoader_Normal.h"
|
||||
#include "VertexLoader_Color.h"
|
||||
#include "VertexLoader_TextCoord.h"
|
||||
|
||||
#include "CPMemLoader.h"
|
||||
#include "XFMemLoader.h"
|
||||
|
||||
#include "TransformUnit.h"
|
||||
#include "SetupUnit.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "VertexManagerBase.h"
|
||||
#include "DataReader.h"
|
||||
|
||||
// Vertex loaders read these
|
||||
extern int tcIndex;
|
||||
extern int colIndex;
|
||||
extern int colElements[2];
|
||||
extern float posScale;
|
||||
extern float tcScale[8];
|
||||
|
||||
|
||||
SWVertexLoader::SWVertexLoader() :
|
||||
m_VertexSize(0),
|
||||
m_NumAttributeLoaders(0)
|
||||
{
|
||||
VertexLoader_Normal::Init();
|
||||
VertexLoader_Position::Init();
|
||||
VertexLoader_TextCoord::Init();
|
||||
|
||||
m_SetupUnit = new SetupUnit;
|
||||
}
|
||||
|
||||
SWVertexLoader::~SWVertexLoader()
|
||||
{
|
||||
delete m_SetupUnit;
|
||||
m_SetupUnit = NULL;
|
||||
}
|
||||
|
||||
void SWVertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
|
||||
{
|
||||
m_CurrentVat = &g_VtxAttr[attributeIndex];
|
||||
|
||||
posScale = 1.0f / float(1 << m_CurrentVat->g0.PosFrac);
|
||||
tcScale[0] = 1.0f / float(1 << m_CurrentVat->g0.Tex0Frac);
|
||||
tcScale[1] = 1.0f / float(1 << m_CurrentVat->g1.Tex1Frac);
|
||||
tcScale[2] = 1.0f / float(1 << m_CurrentVat->g1.Tex2Frac);
|
||||
tcScale[3] = 1.0f / float(1 << m_CurrentVat->g1.Tex3Frac);
|
||||
tcScale[4] = 1.0f / float(1 << m_CurrentVat->g2.Tex4Frac);
|
||||
tcScale[5] = 1.0f / float(1 << m_CurrentVat->g2.Tex5Frac);
|
||||
tcScale[6] = 1.0f / float(1 << m_CurrentVat->g2.Tex6Frac);
|
||||
tcScale[7] = 1.0f / float(1 << m_CurrentVat->g2.Tex7Frac);
|
||||
|
||||
//TexMtx
|
||||
const u32 tmDesc[8] = {
|
||||
g_VtxDesc.Tex0MatIdx, g_VtxDesc.Tex1MatIdx, g_VtxDesc.Tex2MatIdx, g_VtxDesc.Tex3MatIdx,
|
||||
g_VtxDesc.Tex4MatIdx, g_VtxDesc.Tex5MatIdx, g_VtxDesc.Tex6MatIdx, g_VtxDesc.Tex7MatIdx
|
||||
};
|
||||
|
||||
// Colors
|
||||
const u32 colDesc[2] = {g_VtxDesc.Color0, g_VtxDesc.Color1};
|
||||
colElements[0] = m_CurrentVat->g0.Color0Elements;
|
||||
colElements[1] = m_CurrentVat->g0.Color1Elements;
|
||||
const u32 colComp[2] = {m_CurrentVat->g0.Color0Comp, m_CurrentVat->g0.Color1Comp};
|
||||
|
||||
// TextureCoord
|
||||
const u32 tcDesc[8] = {
|
||||
g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord,
|
||||
g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const u32)((g_VtxDesc.Hex >> 31) & 3)
|
||||
};
|
||||
const u32 tcElements[8] = {
|
||||
m_CurrentVat->g0.Tex0CoordElements, m_CurrentVat->g1.Tex1CoordElements, m_CurrentVat->g1.Tex2CoordElements,
|
||||
m_CurrentVat->g1.Tex3CoordElements, m_CurrentVat->g1.Tex4CoordElements, m_CurrentVat->g2.Tex5CoordElements,
|
||||
m_CurrentVat->g2.Tex6CoordElements, m_CurrentVat->g2.Tex7CoordElements
|
||||
};
|
||||
|
||||
const u32 tcFormat[8] = {
|
||||
m_CurrentVat->g0.Tex0CoordFormat, m_CurrentVat->g1.Tex1CoordFormat, m_CurrentVat->g1.Tex2CoordFormat,
|
||||
m_CurrentVat->g1.Tex3CoordFormat, m_CurrentVat->g1.Tex4CoordFormat, m_CurrentVat->g2.Tex5CoordFormat,
|
||||
m_CurrentVat->g2.Tex6CoordFormat, m_CurrentVat->g2.Tex7CoordFormat
|
||||
};
|
||||
|
||||
m_VertexSize = 0;
|
||||
|
||||
// Reset pipeline
|
||||
m_positionLoader = NULL;
|
||||
m_normalLoader = NULL;
|
||||
m_NumAttributeLoaders = 0;
|
||||
|
||||
// Reset vertex
|
||||
// matrix index from xf regs or cp memory?
|
||||
if (swxfregs.MatrixIndexA.PosNormalMtxIdx != MatrixIndexA.PosNormalMtxIdx ||
|
||||
swxfregs.MatrixIndexA.Tex0MtxIdx != MatrixIndexA.Tex0MtxIdx ||
|
||||
swxfregs.MatrixIndexA.Tex1MtxIdx != MatrixIndexA.Tex1MtxIdx ||
|
||||
swxfregs.MatrixIndexA.Tex2MtxIdx != MatrixIndexA.Tex2MtxIdx ||
|
||||
swxfregs.MatrixIndexA.Tex3MtxIdx != MatrixIndexA.Tex3MtxIdx ||
|
||||
swxfregs.MatrixIndexB.Tex4MtxIdx != MatrixIndexB.Tex4MtxIdx ||
|
||||
swxfregs.MatrixIndexB.Tex5MtxIdx != MatrixIndexB.Tex5MtxIdx ||
|
||||
swxfregs.MatrixIndexB.Tex6MtxIdx != MatrixIndexB.Tex6MtxIdx ||
|
||||
swxfregs.MatrixIndexB.Tex7MtxIdx != MatrixIndexB.Tex7MtxIdx)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Matrix indices don't match");
|
||||
|
||||
// Just show the assert once
|
||||
static bool showedAlert = false;
|
||||
_assert_msg_(VIDEO, showedAlert, "Matrix indices don't match");
|
||||
showedAlert = true;
|
||||
}
|
||||
|
||||
#if(1)
|
||||
m_Vertex.posMtx = swxfregs.MatrixIndexA.PosNormalMtxIdx;
|
||||
m_Vertex.texMtx[0] = swxfregs.MatrixIndexA.Tex0MtxIdx;
|
||||
m_Vertex.texMtx[1] = swxfregs.MatrixIndexA.Tex1MtxIdx;
|
||||
m_Vertex.texMtx[2] = swxfregs.MatrixIndexA.Tex2MtxIdx;
|
||||
m_Vertex.texMtx[3] = swxfregs.MatrixIndexA.Tex3MtxIdx;
|
||||
m_Vertex.texMtx[4] = swxfregs.MatrixIndexB.Tex4MtxIdx;
|
||||
m_Vertex.texMtx[5] = swxfregs.MatrixIndexB.Tex5MtxIdx;
|
||||
m_Vertex.texMtx[6] = swxfregs.MatrixIndexB.Tex6MtxIdx;
|
||||
m_Vertex.texMtx[7] = swxfregs.MatrixIndexB.Tex7MtxIdx;
|
||||
#else
|
||||
m_Vertex.posMtx = MatrixIndexA.PosNormalMtxIdx;
|
||||
m_Vertex.texMtx[0] = MatrixIndexA.Tex0MtxIdx;
|
||||
m_Vertex.texMtx[1] = MatrixIndexA.Tex1MtxIdx;
|
||||
m_Vertex.texMtx[2] = MatrixIndexA.Tex2MtxIdx;
|
||||
m_Vertex.texMtx[3] = MatrixIndexA.Tex3MtxIdx;
|
||||
m_Vertex.texMtx[4] = MatrixIndexB.Tex4MtxIdx;
|
||||
m_Vertex.texMtx[5] = MatrixIndexB.Tex5MtxIdx;
|
||||
m_Vertex.texMtx[6] = MatrixIndexB.Tex6MtxIdx;
|
||||
m_Vertex.texMtx[7] = MatrixIndexB.Tex7MtxIdx;
|
||||
#endif
|
||||
|
||||
if (g_VtxDesc.PosMatIdx != NOT_PRESENT)
|
||||
{
|
||||
AddAttributeLoader(LoadPosMtx);
|
||||
m_VertexSize++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (tmDesc[i] != NOT_PRESENT)
|
||||
{
|
||||
AddAttributeLoader(LoadTexMtx, i);
|
||||
m_VertexSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// Write vertex position loader
|
||||
m_positionLoader = VertexLoader_Position::GetFunction(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
|
||||
m_VertexSize += VertexLoader_Position::GetSize(g_VtxDesc.Position, m_CurrentVat->g0.PosFormat, m_CurrentVat->g0.PosElements);
|
||||
AddAttributeLoader(LoadPosition);
|
||||
|
||||
// Normals
|
||||
if (g_VtxDesc.Normal != NOT_PRESENT)
|
||||
{
|
||||
m_VertexSize += VertexLoader_Normal::GetSize(g_VtxDesc.Normal,
|
||||
m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3);
|
||||
|
||||
m_normalLoader = VertexLoader_Normal::GetFunction(g_VtxDesc.Normal,
|
||||
m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3);
|
||||
|
||||
if (m_normalLoader == 0)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "VertexLoader_Normal::GetFunction returned zero!");
|
||||
}
|
||||
AddAttributeLoader(LoadNormal);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
switch (colDesc[i])
|
||||
{
|
||||
case NOT_PRESENT:
|
||||
m_colorLoader[i] = NULL;
|
||||
break;
|
||||
case DIRECT:
|
||||
switch (colComp[i])
|
||||
{
|
||||
case FORMAT_16B_565: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_565); break;
|
||||
case FORMAT_24B_888: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_888); break;
|
||||
case FORMAT_32B_888x: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_888x); break;
|
||||
case FORMAT_16B_4444: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_4444); break;
|
||||
case FORMAT_24B_6666: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_6666); break;
|
||||
case FORMAT_32B_8888: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_8888); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadColor, i);
|
||||
break;
|
||||
case INDEX8:
|
||||
m_VertexSize += 1;
|
||||
switch (colComp[i])
|
||||
{
|
||||
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex8_16b_565); break;
|
||||
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex8_24b_888); break;
|
||||
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex8_32b_888x); break;
|
||||
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex8_16b_4444); break;
|
||||
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex8_24b_6666); break;
|
||||
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex8_32b_8888); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadColor, i);
|
||||
break;
|
||||
case INDEX16:
|
||||
m_VertexSize += 2;
|
||||
switch (colComp[i])
|
||||
{
|
||||
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex16_16b_565); break;
|
||||
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex16_24b_888); break;
|
||||
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex16_32b_888x); break;
|
||||
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex16_16b_4444); break;
|
||||
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex16_24b_6666); break;
|
||||
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex16_32b_8888); break;
|
||||
default: _assert_(0); break;
|
||||
}
|
||||
AddAttributeLoader(LoadColor, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
const int desc = tcDesc[i];
|
||||
const int format = tcFormat[i];
|
||||
const int elements = tcElements[i];
|
||||
_assert_msg_(VIDEO, NOT_PRESENT <= desc && desc <= INDEX16, "Invalid texture coordinates description!\n(desc = %d)", desc);
|
||||
_assert_msg_(VIDEO, FORMAT_UBYTE <= format && format <= FORMAT_FLOAT, "Invalid texture coordinates format!\n(format = %d)", format);
|
||||
_assert_msg_(VIDEO, 0 <= elements && elements <= 1, "Invalid number of texture coordinates elements!\n(elements = %d)", elements);
|
||||
|
||||
m_texCoordLoader[i] = VertexLoader_TextCoord::GetFunction(desc, format, elements);
|
||||
m_VertexSize += VertexLoader_TextCoord::GetSize(desc, format, elements);
|
||||
if (m_texCoordLoader[i])
|
||||
AddAttributeLoader(LoadTexCoord, i);
|
||||
}
|
||||
|
||||
// special case if only pos and tex coord 0 and tex coord input is AB11
|
||||
m_TexGenSpecialCase =
|
||||
((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0
|
||||
(g_VtxDesc.Tex0Coord != NOT_PRESENT) &&
|
||||
(swxfregs.texMtxInfo[0].projection == XF_TEXPROJ_ST);
|
||||
|
||||
m_SetupUnit->Init(primitiveType);
|
||||
}
|
||||
|
||||
|
||||
void SWVertexLoader::LoadVertex()
|
||||
{
|
||||
for (int i = 0; i < m_NumAttributeLoaders; i++)
|
||||
m_AttributeLoaders[i].loader(this, &m_Vertex, m_AttributeLoaders[i].index);
|
||||
|
||||
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
|
||||
|
||||
// transform input data
|
||||
TransformUnit::TransformPosition(&m_Vertex, outVertex);
|
||||
|
||||
if (g_VtxDesc.Normal != NOT_PRESENT)
|
||||
{
|
||||
TransformUnit::TransformNormal(&m_Vertex, m_CurrentVat->g0.NormalElements, outVertex);
|
||||
}
|
||||
|
||||
TransformUnit::TransformColor(&m_Vertex, outVertex);
|
||||
|
||||
TransformUnit::TransformTexCoord(&m_Vertex, outVertex, m_TexGenSpecialCase);
|
||||
|
||||
m_SetupUnit->SetupVertex();
|
||||
|
||||
INCSTAT(swstats.thisFrame.numVerticesLoaded)
|
||||
}
|
||||
|
||||
void SWVertexLoader::AddAttributeLoader(AttributeLoader loader, u8 index)
|
||||
{
|
||||
_assert_msg_(VIDEO, m_NumAttributeLoaders < 21, "Too many attribute loaders");
|
||||
m_AttributeLoaders[m_NumAttributeLoaders].loader = loader;
|
||||
m_AttributeLoaders[m_NumAttributeLoaders++].index = index;
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadPosMtx(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
|
||||
{
|
||||
vertex->posMtx = DataReadU8() & 0x3f;
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadTexMtx(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
|
||||
{
|
||||
vertex->texMtx[index] = DataReadU8() & 0x3f;
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadPosition(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
|
||||
{
|
||||
VertexManager::s_pCurBufferPointer = (u8*)&vertex->position;
|
||||
vertexLoader->m_positionLoader();
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadNormal(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
|
||||
{
|
||||
VertexManager::s_pCurBufferPointer = (u8*)&vertex->normal;
|
||||
vertexLoader->m_normalLoader();
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadColor(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
|
||||
{
|
||||
u32 color;
|
||||
VertexManager::s_pCurBufferPointer = (u8*)&color;
|
||||
colIndex = index;
|
||||
vertexLoader->m_colorLoader[index]();
|
||||
|
||||
// rgba -> abgr
|
||||
*(u32*)vertex->color[index] = Common::swap32(color);
|
||||
}
|
||||
|
||||
void SWVertexLoader::LoadTexCoord(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
|
||||
{
|
||||
VertexManager::s_pCurBufferPointer = (u8*)&vertex->texCoords[index];
|
||||
tcIndex = index;
|
||||
vertexLoader->m_texCoordLoader[index]();
|
||||
}
|
||||
|
||||
void SWVertexLoader::DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoArray(m_AttributeLoaders, sizeof m_AttributeLoaders);
|
||||
p.Do(m_VertexSize);
|
||||
p.Do(*m_CurrentVat);
|
||||
p.Do(m_positionLoader);
|
||||
p.Do(m_normalLoader);
|
||||
p.DoArray(m_colorLoader, sizeof m_colorLoader);
|
||||
p.Do(m_NumAttributeLoaders);
|
||||
m_SetupUnit->DoState(p);
|
||||
p.Do(m_TexGenSpecialCase);
|
||||
}
|
63
Source/Core/VideoBackends/Software/Src/SWVertexLoader.h
Normal file
63
Source/Core/VideoBackends/Software/Src/SWVertexLoader.h
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VERTEXLOADER_H_
|
||||
#define _VERTEXLOADER_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class SetupUnit;
|
||||
|
||||
class SWVertexLoader
|
||||
{
|
||||
u32 m_VertexSize;
|
||||
|
||||
VAT* m_CurrentVat;
|
||||
|
||||
TPipelineFunction m_positionLoader;
|
||||
TPipelineFunction m_normalLoader;
|
||||
TPipelineFunction m_colorLoader[2];
|
||||
TPipelineFunction m_texCoordLoader[8];
|
||||
|
||||
InputVertexData m_Vertex;
|
||||
|
||||
typedef void (*AttributeLoader)(SWVertexLoader*, InputVertexData*, u8);
|
||||
struct AttrLoaderCall
|
||||
{
|
||||
AttributeLoader loader;
|
||||
u8 index;
|
||||
};
|
||||
AttrLoaderCall m_AttributeLoaders[1+8+1+1+2+8];
|
||||
int m_NumAttributeLoaders;
|
||||
void AddAttributeLoader(AttributeLoader loader, u8 index=0);
|
||||
|
||||
// attribute loader functions
|
||||
static void LoadPosMtx(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadTexMtx(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
static void LoadPosition(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadNormal(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
|
||||
static void LoadColor(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
static void LoadTexCoord(SWVertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
|
||||
|
||||
SetupUnit *m_SetupUnit;
|
||||
|
||||
bool m_TexGenSpecialCase;
|
||||
|
||||
public:
|
||||
SWVertexLoader();
|
||||
~SWVertexLoader();
|
||||
|
||||
void SetFormat(u8 attributeIndex, u8 primitiveType);
|
||||
|
||||
u32 GetVertexSize() { return m_VertexSize; }
|
||||
|
||||
void LoadVertex();
|
||||
void DoState(PointerWrap &p);
|
||||
};
|
||||
|
||||
#endif
|
84
Source/Core/VideoBackends/Software/Src/SWVideoConfig.cpp
Normal file
84
Source/Core/VideoBackends/Software/Src/SWVideoConfig.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "IniFile.h"
|
||||
#include "SWVideoConfig.h"
|
||||
|
||||
SWVideoConfig g_SWVideoConfig;
|
||||
|
||||
SWVideoConfig::SWVideoConfig()
|
||||
{
|
||||
bFullscreen = false;
|
||||
bHideCursor = false;
|
||||
renderToMainframe = false;
|
||||
|
||||
bHwRasterizer = false;
|
||||
|
||||
bShowStats = false;
|
||||
|
||||
bDumpTextures = false;
|
||||
bDumpObjects = false;
|
||||
bDumpFrames = false;
|
||||
|
||||
bZComploc = true;
|
||||
bZFreeze = true;
|
||||
|
||||
bDumpTevStages = false;
|
||||
bDumpTevTextureFetches = false;
|
||||
|
||||
drawStart = 0;
|
||||
drawEnd = 100000;
|
||||
}
|
||||
|
||||
void SWVideoConfig::Load(const char* ini_file)
|
||||
{
|
||||
IniFile iniFile;
|
||||
iniFile.Load(ini_file);
|
||||
|
||||
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
|
||||
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
|
||||
|
||||
iniFile.Get("Rendering", "HwRasterizer", &bHwRasterizer, false);
|
||||
iniFile.Get("Rendering", "ZComploc", &bZComploc, true);
|
||||
iniFile.Get("Rendering", "ZFreeze", &bZFreeze, true);
|
||||
|
||||
iniFile.Get("Info", "ShowStats", &bShowStats, false);
|
||||
|
||||
iniFile.Get("Utility", "DumpTexture", &bDumpTextures, false);
|
||||
iniFile.Get("Utility", "DumpObjects", &bDumpObjects, false);
|
||||
iniFile.Get("Utility", "DumpFrames", &bDumpFrames, false);
|
||||
iniFile.Get("Utility", "DumpTevStages", &bDumpTevStages, false);
|
||||
iniFile.Get("Utility", "DumpTevTexFetches", &bDumpTevTextureFetches, false);
|
||||
|
||||
iniFile.Get("Misc", "DrawStart", &drawStart, 0);
|
||||
iniFile.Get("Misc", "DrawEnd", &drawEnd, 100000);
|
||||
}
|
||||
|
||||
void SWVideoConfig::Save(const char* ini_file)
|
||||
{
|
||||
IniFile iniFile;
|
||||
iniFile.Load(ini_file);
|
||||
|
||||
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
|
||||
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
|
||||
|
||||
iniFile.Set("Rendering", "HwRasterizer", bHwRasterizer);
|
||||
iniFile.Set("Rendering", "ZComploc", &bZComploc);
|
||||
iniFile.Set("Rendering", "ZFreeze", &bZFreeze);
|
||||
|
||||
iniFile.Set("Info", "ShowStats", bShowStats);
|
||||
|
||||
iniFile.Set("Utility", "DumpTexture", bDumpTextures);
|
||||
iniFile.Set("Utility", "DumpObjects", bDumpObjects);
|
||||
iniFile.Set("Utility", "DumpFrames", bDumpFrames);
|
||||
iniFile.Set("Utility", "DumpTevStages", bDumpTevStages);
|
||||
iniFile.Set("Utility", "DumpTevTexFetches", bDumpTevTextureFetches);
|
||||
|
||||
iniFile.Set("Misc", "DrawStart", drawStart);
|
||||
iniFile.Set("Misc", "DrawEnd", drawEnd);
|
||||
|
||||
iniFile.Save(ini_file);
|
||||
}
|
||||
|
46
Source/Core/VideoBackends/Software/Src/SWVideoConfig.h
Normal file
46
Source/Core/VideoBackends/Software/Src/SWVideoConfig.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VIDEOSOFTWARE_CONFIG_H_
|
||||
#define _VIDEOSOFTWARE_CONFIG_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#define STATISTICS 1
|
||||
|
||||
// NEVER inherit from this class.
|
||||
struct SWVideoConfig : NonCopyable
|
||||
{
|
||||
SWVideoConfig();
|
||||
void Load(const char* ini_file);
|
||||
void Save(const char* ini_file);
|
||||
|
||||
// General
|
||||
bool bFullscreen;
|
||||
bool bHideCursor;
|
||||
bool renderToMainframe;
|
||||
|
||||
bool bHwRasterizer;
|
||||
|
||||
// Emulation features
|
||||
bool bZComploc;
|
||||
bool bZFreeze;
|
||||
|
||||
bool bShowStats;
|
||||
|
||||
bool bDumpTextures;
|
||||
bool bDumpObjects;
|
||||
bool bDumpFrames;
|
||||
|
||||
// Debug only
|
||||
bool bDumpTevStages;
|
||||
bool bDumpTevTextureFetches;
|
||||
|
||||
u32 drawStart;
|
||||
u32 drawEnd;
|
||||
};
|
||||
|
||||
extern SWVideoConfig g_SWVideoConfig;
|
||||
|
||||
#endif // _VIDEOSOFTWARE_CONFIG_H_
|
345
Source/Core/VideoBackends/Software/Src/SWmain.cpp
Normal file
345
Source/Core/VideoBackends/Software/Src/SWmain.cpp
Normal file
@ -0,0 +1,345 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include "VideoConfigDialog.h"
|
||||
#endif // HAVE_WX
|
||||
|
||||
|
||||
#include "SWCommandProcessor.h"
|
||||
#include "OpcodeDecoder.h"
|
||||
#include "SWVideoConfig.h"
|
||||
#include "SWPixelEngine.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "Clipper.h"
|
||||
#include "Rasterizer.h"
|
||||
#include "SWRenderer.h"
|
||||
#include "HwRasterizer.h"
|
||||
#include "LogManager.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "DebugUtil.h"
|
||||
#include "FileUtil.h"
|
||||
#include "VideoBackend.h"
|
||||
#include "Core.h"
|
||||
#include "OpcodeDecoder.h"
|
||||
#include "SWVertexLoader.h"
|
||||
#include "SWStatistics.h"
|
||||
|
||||
#include "OnScreenDisplay.h"
|
||||
#define VSYNC_ENABLED 0
|
||||
|
||||
namespace SW
|
||||
{
|
||||
|
||||
static volatile bool fifoStateRun = false;
|
||||
static volatile bool emuRunningState = false;
|
||||
static std::mutex m_csSWVidOccupied;
|
||||
|
||||
std::string VideoSoftware::GetName()
|
||||
{
|
||||
return _trans("Software Renderer");
|
||||
}
|
||||
|
||||
void *DllDebugger(void *_hParent, bool Show)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void VideoSoftware::ShowConfig(void *_hParent)
|
||||
{
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
VideoConfigDialog diag((wxWindow*)_hParent, "Software", "gfx_software");
|
||||
diag.ShowModal();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoSoftware::Initialize(void *&window_handle)
|
||||
{
|
||||
g_SWVideoConfig.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_software.ini").c_str());
|
||||
InitInterface();
|
||||
|
||||
if (!GLInterface->Create(window_handle))
|
||||
{
|
||||
INFO_LOG(VIDEO, "%s", "SWRenderer::Create failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
InitBPMemory();
|
||||
InitXFMemory();
|
||||
SWCommandProcessor::Init();
|
||||
SWPixelEngine::Init();
|
||||
OpcodeDecoder::Init();
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
HwRasterizer::Init();
|
||||
SWRenderer::Init();
|
||||
DebugUtil::Init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoSoftware::DoState(PointerWrap& p)
|
||||
{
|
||||
bool software = true;
|
||||
p.Do(software);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ && software == false)
|
||||
// change mode to abort load of incompatible save state.
|
||||
p.SetMode(PointerWrap::MODE_VERIFY);
|
||||
|
||||
// TODO: incomplete?
|
||||
SWCommandProcessor::DoState(p);
|
||||
SWPixelEngine::DoState(p);
|
||||
EfbInterface::DoState(p);
|
||||
OpcodeDecoder::DoState(p);
|
||||
Clipper::DoState(p);
|
||||
p.Do(swxfregs);
|
||||
p.Do(bpmem);
|
||||
p.DoPOD(swstats);
|
||||
|
||||
// CP Memory
|
||||
p.DoArray(arraybases, 16);
|
||||
p.DoArray(arraystrides, 16);
|
||||
p.Do(MatrixIndexA);
|
||||
p.Do(MatrixIndexB);
|
||||
p.Do(g_VtxDesc.Hex);
|
||||
p.DoArray(g_VtxAttr, 8);
|
||||
p.DoMarker("CP Memory");
|
||||
|
||||
}
|
||||
|
||||
void VideoSoftware::CheckInvalidState()
|
||||
{
|
||||
// there is no state to invalidate
|
||||
}
|
||||
|
||||
void VideoSoftware::PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
||||
{
|
||||
if (doLock)
|
||||
{
|
||||
EmuStateChange(EMUSTATE_CHANGE_PAUSE);
|
||||
if (!Core::IsGPUThread())
|
||||
m_csSWVidOccupied.lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unpauseOnUnlock)
|
||||
EmuStateChange(EMUSTATE_CHANGE_PLAY);
|
||||
if (!Core::IsGPUThread())
|
||||
m_csSWVidOccupied.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoSoftware::RunLoop(bool enable)
|
||||
{
|
||||
emuRunningState = enable;
|
||||
}
|
||||
|
||||
void VideoSoftware::EmuStateChange(EMUSTATE_CHANGE newState)
|
||||
{
|
||||
emuRunningState = (newState == EMUSTATE_CHANGE_PLAY) ? true : false;
|
||||
}
|
||||
|
||||
void VideoSoftware::Shutdown()
|
||||
{
|
||||
// TODO: should be in Video_Cleanup
|
||||
HwRasterizer::Shutdown();
|
||||
SWRenderer::Shutdown();
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::OSD_SHUTDOWN);
|
||||
|
||||
GLInterface->Shutdown();
|
||||
}
|
||||
|
||||
void VideoSoftware::Video_Cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
// This is called after Video_Initialize() from the Core
|
||||
void VideoSoftware::Video_Prepare()
|
||||
{
|
||||
GLInterface->MakeCurrent();
|
||||
// Init extension support.
|
||||
#ifndef USE_GLES
|
||||
#ifdef __APPLE__
|
||||
glewExperimental = 1;
|
||||
#endif
|
||||
if (glewInit() != GLEW_OK) {
|
||||
ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// Handle VSync on/off
|
||||
GLInterface->SwapInterval(VSYNC_ENABLED);
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::OSD_INIT);
|
||||
|
||||
HwRasterizer::Prepare();
|
||||
SWRenderer::Prepare();
|
||||
|
||||
INFO_LOG(VIDEO, "Video backend initialized.");
|
||||
}
|
||||
|
||||
// Run from the CPU thread (from VideoInterface.cpp)
|
||||
void VideoSoftware::Video_BeginField(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
}
|
||||
|
||||
// Run from the CPU thread (from VideoInterface.cpp)
|
||||
void VideoSoftware::Video_EndField()
|
||||
{
|
||||
}
|
||||
|
||||
u32 VideoSoftware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
|
||||
{
|
||||
u32 value = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PEEK_Z:
|
||||
{
|
||||
value = EfbInterface::GetDepth(x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
case POKE_Z:
|
||||
break;
|
||||
|
||||
case PEEK_COLOR:
|
||||
{
|
||||
u32 color = 0;
|
||||
EfbInterface::GetColor(x, y, (u8*)&color);
|
||||
|
||||
// rgba to argb
|
||||
value = (color >> 8) | (color & 0xff) << 24;
|
||||
break;
|
||||
}
|
||||
|
||||
case POKE_COLOR:
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
u32 VideoSoftware::Video_GetQueryResult(PerfQueryType type)
|
||||
{
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool VideoSoftware::Video_Screenshot(const char *_szFilename)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Enter and exit the video loop
|
||||
// -------------------------------
|
||||
void VideoSoftware::Video_EnterLoop()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_csSWVidOccupied);
|
||||
fifoStateRun = true;
|
||||
|
||||
while (fifoStateRun)
|
||||
{
|
||||
g_video_backend->PeekMessages();
|
||||
|
||||
if (!SWCommandProcessor::RunBuffer())
|
||||
{
|
||||
Common::YieldCPU();
|
||||
}
|
||||
|
||||
while (!emuRunningState && fifoStateRun)
|
||||
{
|
||||
g_video_backend->PeekMessages();
|
||||
m_csSWVidOccupied.unlock();
|
||||
Common::SleepCurrentThread(1);
|
||||
m_csSWVidOccupied.lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoSoftware::Video_ExitLoop()
|
||||
{
|
||||
fifoStateRun = false;
|
||||
}
|
||||
|
||||
// TODO : could use the OSD class in video common, we would need to implement the Renderer class
|
||||
// however most of it is useless for the SW backend so we could as well move it to its own class
|
||||
void VideoSoftware::Video_AddMessage(const char* pstr, u32 milliseconds)
|
||||
{
|
||||
}
|
||||
void VideoSoftware::Video_ClearMessages()
|
||||
{
|
||||
}
|
||||
|
||||
void VideoSoftware::Video_SetRendering(bool bEnabled)
|
||||
{
|
||||
SWCommandProcessor::SetRendering(bEnabled);
|
||||
}
|
||||
|
||||
void VideoSoftware::Video_GatherPipeBursted()
|
||||
{
|
||||
SWCommandProcessor::GatherPipeBursted();
|
||||
}
|
||||
|
||||
bool VideoSoftware::Video_IsPossibleWaitingSetDrawDone(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoSoftware::Video_IsHiWatermarkActive(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void VideoSoftware::Video_AbortFrame(void)
|
||||
{
|
||||
}
|
||||
|
||||
readFn16 VideoSoftware::Video_CPRead16()
|
||||
{
|
||||
return SWCommandProcessor::Read16;
|
||||
}
|
||||
writeFn16 VideoSoftware::Video_CPWrite16()
|
||||
{
|
||||
return SWCommandProcessor::Write16;
|
||||
}
|
||||
|
||||
readFn16 VideoSoftware::Video_PERead16()
|
||||
{
|
||||
return SWPixelEngine::Read16;
|
||||
}
|
||||
writeFn16 VideoSoftware::Video_PEWrite16()
|
||||
{
|
||||
return SWPixelEngine::Write16;
|
||||
}
|
||||
writeFn32 VideoSoftware::Video_PEWrite32()
|
||||
{
|
||||
return SWPixelEngine::Write32;
|
||||
}
|
||||
|
||||
|
||||
// Draw messages on top of the screen
|
||||
unsigned int VideoSoftware::PeekMessages()
|
||||
{
|
||||
return GLInterface->PeekMessages();
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
void VideoSoftware::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
char temp[100];
|
||||
snprintf(temp, sizeof temp, "%s | Software | %s", scm_rev_str, text);
|
||||
GLInterface->UpdateFPSDisplay(temp);
|
||||
}
|
||||
|
||||
}
|
176
Source/Core/VideoBackends/Software/Src/SetupUnit.cpp
Normal file
176
Source/Core/VideoBackends/Software/Src/SetupUnit.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "SetupUnit.h"
|
||||
|
||||
#include "CPMemLoader.h"
|
||||
#include "OpcodeDecoder.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "Clipper.h"
|
||||
|
||||
|
||||
void SetupUnit::Init(u8 primitiveType)
|
||||
{
|
||||
m_PrimType = primitiveType;
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertPointer[0] = &m_Vertices[0];
|
||||
m_VertPointer[1] = &m_Vertices[1];
|
||||
m_VertPointer[2] = &m_Vertices[2];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupVertex()
|
||||
{
|
||||
switch(m_PrimType)
|
||||
{
|
||||
case GX_DRAW_QUADS:
|
||||
SetupQuad();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLES:
|
||||
SetupTriangle();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_STRIP:
|
||||
SetupTriStrip();
|
||||
break;
|
||||
case GX_DRAW_TRIANGLE_FAN:
|
||||
SetupTriFan();
|
||||
break;
|
||||
case GX_DRAW_LINES:
|
||||
SetupLine();
|
||||
break;
|
||||
case GX_DRAW_LINE_STRIP:
|
||||
SetupLineStrip();
|
||||
break;
|
||||
case GX_DRAW_POINTS:
|
||||
SetupPoint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetupUnit::SetupQuad()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertexCounter &= 3;
|
||||
m_VertWritePointer = &m_Vertices[m_VertexCounter & 1];
|
||||
OutputVertexData* temp = m_VertPointer[1];
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = temp;
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriangle()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriStrip()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
|
||||
m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupTriFan()
|
||||
{
|
||||
if (m_VertexCounter < 2)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
|
||||
|
||||
m_VertexCounter++;
|
||||
m_VertPointer[1] = m_VertPointer[2];
|
||||
m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)];
|
||||
|
||||
m_VertWritePointer = m_VertPointer[2];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupLine()
|
||||
{
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
|
||||
m_VertexCounter = 0;
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupLineStrip()
|
||||
{
|
||||
if (m_VertexCounter < 1)
|
||||
{
|
||||
m_VertexCounter++;
|
||||
m_VertWritePointer = m_VertPointer[m_VertexCounter];
|
||||
return;
|
||||
}
|
||||
|
||||
m_VertexCounter++;
|
||||
|
||||
Clipper::ProcessLine(m_VertPointer[0], m_VertPointer[1]);
|
||||
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
|
||||
m_VertPointer[0] = m_VertPointer[1];
|
||||
m_VertPointer[1] = &m_Vertices[m_VertexCounter & 1];
|
||||
}
|
||||
|
||||
void SetupUnit::SetupPoint()
|
||||
{}
|
||||
|
||||
void SetupUnit::DoState(PointerWrap &p)
|
||||
{
|
||||
// TODO: some or all of this is making the save states stop working once dolphin is closed...sometimes (usually)
|
||||
// I have no idea what specifically is wrong, or if this is even important. Disabling it doesn't seem to make any noticible difference...
|
||||
/* p.Do(m_PrimType);
|
||||
p.Do(m_VertexCounter);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
m_Vertices[i].DoState(p);
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
m_VertPointer[0] = &m_Vertices[0];
|
||||
m_VertPointer[1] = &m_Vertices[1];
|
||||
m_VertPointer[2] = &m_Vertices[2];
|
||||
m_VertWritePointer = m_VertPointer[0];
|
||||
}*/
|
||||
}
|
39
Source/Core/VideoBackends/Software/Src/SetupUnit.h
Normal file
39
Source/Core/VideoBackends/Software/Src/SetupUnit.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
#ifndef _SETUPUNIT_H_
|
||||
#define _SETUPUNIT_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class SetupUnit
|
||||
{
|
||||
u8 m_PrimType;
|
||||
int m_VertexCounter;
|
||||
|
||||
OutputVertexData m_Vertices[3];
|
||||
OutputVertexData *m_VertPointer[3];
|
||||
OutputVertexData *m_VertWritePointer;
|
||||
|
||||
void SetupQuad();
|
||||
void SetupTriangle();
|
||||
void SetupTriStrip();
|
||||
void SetupTriFan();
|
||||
void SetupLine();
|
||||
void SetupLineStrip();
|
||||
void SetupPoint();
|
||||
|
||||
public:
|
||||
void Init(u8 primitiveType);
|
||||
|
||||
OutputVertexData* GetVertex() { return m_VertWritePointer; }
|
||||
|
||||
void SetupVertex();
|
||||
void DoState(PointerWrap &p);
|
||||
};
|
||||
|
||||
#endif
|
874
Source/Core/VideoBackends/Software/Src/Tev.cpp
Normal file
874
Source/Core/VideoBackends/Software/Src/Tev.cpp
Normal file
@ -0,0 +1,874 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "Tev.h"
|
||||
#include "EfbInterface.h"
|
||||
#include "TextureSampler.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "SWPixelEngine.h"
|
||||
#include "SWStatistics.h"
|
||||
#include "SWVideoConfig.h"
|
||||
#include "DebugUtil.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define ALLOW_TEV_DUMPS 1
|
||||
#else
|
||||
#define ALLOW_TEV_DUMPS 0
|
||||
#endif
|
||||
|
||||
void Tev::Init()
|
||||
{
|
||||
FixedConstants[0] = 0;
|
||||
FixedConstants[1] = 31;
|
||||
FixedConstants[2] = 63;
|
||||
FixedConstants[3] = 95;
|
||||
FixedConstants[4] = 127;
|
||||
FixedConstants[5] = 159;
|
||||
FixedConstants[6] = 191;
|
||||
FixedConstants[7] = 223;
|
||||
FixedConstants[8] = 255;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
Zero16[i] = 0;
|
||||
|
||||
m_ColorInputLUT[0][RED_INP] = &Reg[0][RED_C]; m_ColorInputLUT[0][GRN_INP] = &Reg[0][GRN_C]; m_ColorInputLUT[0][BLU_INP] = &Reg[0][BLU_C]; // prev.rgb
|
||||
m_ColorInputLUT[1][RED_INP] = &Reg[0][ALP_C]; m_ColorInputLUT[1][GRN_INP] = &Reg[0][ALP_C]; m_ColorInputLUT[1][BLU_INP] = &Reg[0][ALP_C]; // prev.aaa
|
||||
m_ColorInputLUT[2][RED_INP] = &Reg[1][RED_C]; m_ColorInputLUT[2][GRN_INP] = &Reg[1][GRN_C]; m_ColorInputLUT[2][BLU_INP] = &Reg[1][BLU_C]; // c0.rgb
|
||||
m_ColorInputLUT[3][RED_INP] = &Reg[1][ALP_C]; m_ColorInputLUT[3][GRN_INP] = &Reg[1][ALP_C]; m_ColorInputLUT[3][BLU_INP] = &Reg[1][ALP_C]; // c0.aaa
|
||||
m_ColorInputLUT[4][RED_INP] = &Reg[2][RED_C]; m_ColorInputLUT[4][GRN_INP] = &Reg[2][GRN_C]; m_ColorInputLUT[4][BLU_INP] = &Reg[2][BLU_C]; // c1.rgb
|
||||
m_ColorInputLUT[5][RED_INP] = &Reg[2][ALP_C]; m_ColorInputLUT[5][GRN_INP] = &Reg[2][ALP_C]; m_ColorInputLUT[5][BLU_INP] = &Reg[2][ALP_C]; // c1.aaa
|
||||
m_ColorInputLUT[6][RED_INP] = &Reg[3][RED_C]; m_ColorInputLUT[6][GRN_INP] = &Reg[3][GRN_C]; m_ColorInputLUT[6][BLU_INP] = &Reg[3][BLU_C]; // c2.rgb
|
||||
m_ColorInputLUT[7][RED_INP] = &Reg[3][ALP_C]; m_ColorInputLUT[7][GRN_INP] = &Reg[3][ALP_C]; m_ColorInputLUT[7][BLU_INP] = &Reg[3][ALP_C]; // c2.aaa
|
||||
m_ColorInputLUT[8][RED_INP] = &TexColor[RED_C]; m_ColorInputLUT[8][GRN_INP] = &TexColor[GRN_C]; m_ColorInputLUT[8][BLU_INP] = &TexColor[BLU_C]; // tex.rgb
|
||||
m_ColorInputLUT[9][RED_INP] = &TexColor[ALP_C]; m_ColorInputLUT[9][GRN_INP] = &TexColor[ALP_C]; m_ColorInputLUT[9][BLU_INP] = &TexColor[ALP_C]; // tex.aaa
|
||||
m_ColorInputLUT[10][RED_INP] = &RasColor[RED_C]; m_ColorInputLUT[10][GRN_INP] = &RasColor[GRN_C]; m_ColorInputLUT[10][BLU_INP] = &RasColor[BLU_C]; // ras.rgb
|
||||
m_ColorInputLUT[11][RED_INP] = &RasColor[ALP_C]; m_ColorInputLUT[11][GRN_INP] = &RasColor[ALP_C]; m_ColorInputLUT[11][BLU_INP] = &RasColor[ALP_C]; // ras.rgb
|
||||
m_ColorInputLUT[12][RED_INP] = &FixedConstants[8]; m_ColorInputLUT[12][GRN_INP] = &FixedConstants[8]; m_ColorInputLUT[12][BLU_INP] = &FixedConstants[8]; // one
|
||||
m_ColorInputLUT[13][RED_INP] = &FixedConstants[4]; m_ColorInputLUT[13][GRN_INP] = &FixedConstants[4]; m_ColorInputLUT[13][BLU_INP] = &FixedConstants[4]; // half
|
||||
m_ColorInputLUT[14][RED_INP] = &StageKonst[RED_C]; m_ColorInputLUT[14][GRN_INP] = &StageKonst[GRN_C]; m_ColorInputLUT[14][BLU_INP] = &StageKonst[BLU_C]; // konst
|
||||
m_ColorInputLUT[15][RED_INP] = &FixedConstants[0]; m_ColorInputLUT[15][GRN_INP] = &FixedConstants[0]; m_ColorInputLUT[15][BLU_INP] = &FixedConstants[0]; // zero
|
||||
|
||||
m_AlphaInputLUT[0] = Reg[0]; // prev
|
||||
m_AlphaInputLUT[1] = Reg[1]; // c0
|
||||
m_AlphaInputLUT[2] = Reg[2]; // c1
|
||||
m_AlphaInputLUT[3] = Reg[3]; // c2
|
||||
m_AlphaInputLUT[4] = TexColor; // tex
|
||||
m_AlphaInputLUT[5] = RasColor; // ras
|
||||
m_AlphaInputLUT[6] = StageKonst; // konst
|
||||
m_AlphaInputLUT[7] = Zero16; // zero
|
||||
|
||||
for (int comp = 0; comp < 4; comp++)
|
||||
{
|
||||
m_KonstLUT[0][comp] = &FixedConstants[8];
|
||||
m_KonstLUT[1][comp] = &FixedConstants[7];
|
||||
m_KonstLUT[2][comp] = &FixedConstants[6];
|
||||
m_KonstLUT[3][comp] = &FixedConstants[5];
|
||||
m_KonstLUT[4][comp] = &FixedConstants[4];
|
||||
m_KonstLUT[5][comp] = &FixedConstants[3];
|
||||
m_KonstLUT[6][comp] = &FixedConstants[2];
|
||||
m_KonstLUT[7][comp] = &FixedConstants[1];
|
||||
|
||||
m_KonstLUT[12][comp] = &KonstantColors[0][comp];
|
||||
m_KonstLUT[13][comp] = &KonstantColors[1][comp];
|
||||
m_KonstLUT[14][comp] = &KonstantColors[2][comp];
|
||||
m_KonstLUT[15][comp] = &KonstantColors[3][comp];
|
||||
|
||||
m_KonstLUT[16][comp] = &KonstantColors[0][RED_C];
|
||||
m_KonstLUT[17][comp] = &KonstantColors[1][RED_C];
|
||||
m_KonstLUT[18][comp] = &KonstantColors[2][RED_C];
|
||||
m_KonstLUT[19][comp] = &KonstantColors[3][RED_C];
|
||||
m_KonstLUT[20][comp] = &KonstantColors[0][GRN_C];
|
||||
m_KonstLUT[21][comp] = &KonstantColors[1][GRN_C];
|
||||
m_KonstLUT[22][comp] = &KonstantColors[2][GRN_C];
|
||||
m_KonstLUT[23][comp] = &KonstantColors[3][GRN_C];
|
||||
m_KonstLUT[24][comp] = &KonstantColors[0][BLU_C];
|
||||
m_KonstLUT[25][comp] = &KonstantColors[1][BLU_C];
|
||||
m_KonstLUT[26][comp] = &KonstantColors[2][BLU_C];
|
||||
m_KonstLUT[27][comp] = &KonstantColors[3][BLU_C];
|
||||
m_KonstLUT[28][comp] = &KonstantColors[0][ALP_C];
|
||||
m_KonstLUT[29][comp] = &KonstantColors[1][ALP_C];
|
||||
m_KonstLUT[30][comp] = &KonstantColors[2][ALP_C];
|
||||
m_KonstLUT[31][comp] = &KonstantColors[3][ALP_C];
|
||||
}
|
||||
|
||||
m_BiasLUT[0] = 0;
|
||||
m_BiasLUT[1] = 128;
|
||||
m_BiasLUT[2] = -128;
|
||||
m_BiasLUT[3] = 0;
|
||||
|
||||
m_ScaleLShiftLUT[0] = 0;
|
||||
m_ScaleLShiftLUT[1] = 1;
|
||||
m_ScaleLShiftLUT[2] = 2;
|
||||
m_ScaleLShiftLUT[3] = 0;
|
||||
|
||||
m_ScaleRShiftLUT[0] = 0;
|
||||
m_ScaleRShiftLUT[1] = 0;
|
||||
m_ScaleRShiftLUT[2] = 0;
|
||||
m_ScaleRShiftLUT[3] = 1;
|
||||
}
|
||||
|
||||
inline s16 Clamp255(s16 in)
|
||||
{
|
||||
return in>255?255:(in<0?0:in);
|
||||
}
|
||||
|
||||
inline s16 Clamp1024(s16 in)
|
||||
{
|
||||
return in>1023?1023:(in<-1024?-1024:in);
|
||||
}
|
||||
|
||||
void Tev::SetRasColor(int colorChan, int swaptable)
|
||||
{
|
||||
switch(colorChan)
|
||||
{
|
||||
case 0: // Color0
|
||||
{
|
||||
u8 *color = Color[0];
|
||||
RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
break;
|
||||
case 1: // Color1
|
||||
{
|
||||
u8 *color = Color[1];
|
||||
RasColor[RED_C] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[GRN_C] = color[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
RasColor[BLU_C] = color[bpmem.tevksel[swaptable].swap1];
|
||||
RasColor[ALP_C] = color[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
break;
|
||||
case 5: // alpha bump
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = AlphaBump;
|
||||
}
|
||||
break;
|
||||
case 6: // alpha bump normalized
|
||||
{
|
||||
u8 normalized = AlphaBump | AlphaBump >> 5;
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = normalized;
|
||||
}
|
||||
break;
|
||||
default: // zero
|
||||
{
|
||||
for(int i = 0; i < 4; i++)
|
||||
RasColor[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawColorRegular(TevStageCombiner::ColorCombiner &cc)
|
||||
{
|
||||
InputRegType InputReg;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
|
||||
u16 c = InputReg.c + (InputReg.c >> 7);
|
||||
|
||||
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
||||
temp = cc.op?(-temp >> 8):(temp >> 8);
|
||||
|
||||
s32 result = InputReg.d + temp + m_BiasLUT[cc.bias];
|
||||
result = result << m_ScaleLShiftLUT[cc.shift];
|
||||
result = result >> m_ScaleRShiftLUT[cc.shift];
|
||||
|
||||
Reg[cc.dest][BLU_C + i] = result;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawColorCompare(TevStageCombiner::ColorCombiner &cc)
|
||||
{
|
||||
int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here
|
||||
|
||||
u32 a;
|
||||
u32 b;
|
||||
|
||||
InputRegType InputReg;
|
||||
|
||||
switch(cmp) {
|
||||
case TEVCMP_R8_GT:
|
||||
{
|
||||
a = *m_ColorInputLUT[cc.a][RED_INP] & 0xff;
|
||||
b = *m_ColorInputLUT[cc.b][RED_INP] & 0xff;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TEVCMP_R8_EQ:
|
||||
{
|
||||
a = *m_ColorInputLUT[cc.a][RED_INP] & 0xff;
|
||||
b = *m_ColorInputLUT[cc.b][RED_INP] & 0xff;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_GT:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][GRN_INP] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_INP] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][GRN_INP] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_INP] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_EQ:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_INP] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_INP] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_GT:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_INP] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_INP] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_EQ:
|
||||
{
|
||||
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_INP] & 0xff);
|
||||
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_INP] & 0xff);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TEVCMP_RGB8_GT:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_RGB8_EQ:
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
InputReg.a = *m_ColorInputLUT[cc.a][i];
|
||||
InputReg.b = *m_ColorInputLUT[cc.b][i];
|
||||
InputReg.c = *m_ColorInputLUT[cc.c][i];
|
||||
InputReg.d = *m_ColorInputLUT[cc.d][i];
|
||||
Reg[cc.dest][BLU_C + i] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac)
|
||||
{
|
||||
InputRegType InputReg;
|
||||
|
||||
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
|
||||
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
|
||||
u16 c = InputReg.c + (InputReg.c >> 7);
|
||||
|
||||
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
|
||||
temp = ac.op?(-temp >> 8):(temp >> 8);
|
||||
|
||||
s32 result = InputReg.d + temp + m_BiasLUT[ac.bias];
|
||||
result = result << m_ScaleLShiftLUT[ac.shift];
|
||||
result = result >> m_ScaleRShiftLUT[ac.shift];
|
||||
|
||||
Reg[ac.dest][ALP_C] = result;
|
||||
}
|
||||
|
||||
void Tev::DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac)
|
||||
{
|
||||
int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here
|
||||
|
||||
u32 a;
|
||||
u32 b;
|
||||
|
||||
InputRegType InputReg;
|
||||
|
||||
switch(cmp) {
|
||||
case TEVCMP_R8_GT:
|
||||
{
|
||||
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
|
||||
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case TEVCMP_R8_EQ:
|
||||
{
|
||||
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
|
||||
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_GT:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_GR16_EQ:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_GT:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_BGR24_EQ:
|
||||
{
|
||||
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
|
||||
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_A8_GT:
|
||||
{
|
||||
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
|
||||
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
case TEVCMP_A8_EQ:
|
||||
{
|
||||
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
|
||||
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
|
||||
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
|
||||
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
|
||||
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool AlphaCompare(int alpha, int ref, int comp)
|
||||
{
|
||||
switch(comp) {
|
||||
case ALPHACMP_ALWAYS: return true;
|
||||
case ALPHACMP_NEVER: return false;
|
||||
case ALPHACMP_LEQUAL: return alpha <= ref;
|
||||
case ALPHACMP_LESS: return alpha < ref;
|
||||
case ALPHACMP_GEQUAL: return alpha >= ref;
|
||||
case ALPHACMP_GREATER: return alpha > ref;
|
||||
case ALPHACMP_EQUAL: return alpha == ref;
|
||||
case ALPHACMP_NEQUAL: return alpha != ref;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TevAlphaTest(int alpha)
|
||||
{
|
||||
bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0);
|
||||
bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1);
|
||||
|
||||
switch (bpmem.alpha_test.logic)
|
||||
{
|
||||
case 0: return comp0 && comp1; // and
|
||||
case 1: return comp0 || comp1; // or
|
||||
case 2: return comp0 ^ comp1; // xor
|
||||
case 3: return !(comp0 ^ comp1); // xnor
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline s32 WrapIndirectCoord(s32 coord, int wrapMode)
|
||||
{
|
||||
switch (wrapMode)
|
||||
{
|
||||
case ITW_OFF:
|
||||
return coord;
|
||||
case ITW_256:
|
||||
return (coord % (256 << 7));
|
||||
case ITW_128:
|
||||
return (coord % (128 << 7));
|
||||
case ITW_64:
|
||||
return (coord % (64 << 7));
|
||||
case ITW_32:
|
||||
return (coord % (32 << 7));
|
||||
case ITW_16:
|
||||
return (coord % (16 << 7));
|
||||
case ITW_0:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Tev::Indirect(unsigned int stageNum, s32 s, s32 t)
|
||||
{
|
||||
TevStageIndirect &indirect = bpmem.tevind[stageNum];
|
||||
u8 *indmap = IndirectTex[indirect.bt];
|
||||
|
||||
s32 indcoord[3];
|
||||
|
||||
// alpha bump select
|
||||
switch (indirect.bs)
|
||||
{
|
||||
case ITBA_OFF:
|
||||
AlphaBump = 0;
|
||||
break;
|
||||
case ITBA_S:
|
||||
AlphaBump = indmap[TextureSampler::ALP_SMP];
|
||||
break;
|
||||
case ITBA_T:
|
||||
AlphaBump = indmap[TextureSampler::BLU_SMP];
|
||||
break;
|
||||
case ITBA_U:
|
||||
AlphaBump = indmap[TextureSampler::GRN_SMP];
|
||||
break;
|
||||
}
|
||||
|
||||
// bias select
|
||||
s16 biasValue = indirect.fmt==ITF_8?-128:1;
|
||||
s16 bias[3];
|
||||
bias[0] = indirect.bias&1?biasValue:0;
|
||||
bias[1] = indirect.bias&2?biasValue:0;
|
||||
bias[2] = indirect.bias&4?biasValue:0;
|
||||
|
||||
// format
|
||||
switch(indirect.fmt)
|
||||
{
|
||||
case ITF_8:
|
||||
indcoord[0] = indmap[TextureSampler::ALP_SMP] + bias[0];
|
||||
indcoord[1] = indmap[TextureSampler::BLU_SMP] + bias[1];
|
||||
indcoord[2] = indmap[TextureSampler::GRN_SMP] + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf8;
|
||||
break;
|
||||
case ITF_5:
|
||||
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x1f) + bias[0];
|
||||
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x1f) + bias[1];
|
||||
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x1f) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xe0;
|
||||
break;
|
||||
case ITF_4:
|
||||
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x0f) + bias[0];
|
||||
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x0f) + bias[1];
|
||||
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x0f) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf0;
|
||||
break;
|
||||
case ITF_3:
|
||||
indcoord[0] = (indmap[TextureSampler::ALP_SMP] & 0x07) + bias[0];
|
||||
indcoord[1] = (indmap[TextureSampler::BLU_SMP] & 0x07) + bias[1];
|
||||
indcoord[2] = (indmap[TextureSampler::GRN_SMP] & 0x07) + bias[2];
|
||||
AlphaBump = AlphaBump & 0xf8;
|
||||
break;
|
||||
default:
|
||||
PanicAlert("Tev::Indirect");
|
||||
return;
|
||||
}
|
||||
|
||||
s64 indtevtrans[2] = { 0,0 };
|
||||
|
||||
// matrix multiply
|
||||
int indmtxid = indirect.mid & 3;
|
||||
if (indmtxid)
|
||||
{
|
||||
IND_MTX &indmtx = bpmem.indmtx[indmtxid - 1];
|
||||
int scale = ((u32)indmtx.col0.s0 << 0) |
|
||||
((u32)indmtx.col1.s1 << 2) |
|
||||
((u32)indmtx.col2.s2 << 4);
|
||||
|
||||
int shift;
|
||||
|
||||
switch (indirect.mid & 12)
|
||||
{
|
||||
case 0:
|
||||
shift = 3 + (17 - scale);
|
||||
indtevtrans[0] = indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] + indmtx.col2.me * indcoord[2];
|
||||
indtevtrans[1] = indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] + indmtx.col2.mf * indcoord[2];
|
||||
break;
|
||||
case 4: // s matrix
|
||||
shift = 8 + (17 - scale);
|
||||
indtevtrans[0] = s * indcoord[0];
|
||||
indtevtrans[1] = t * indcoord[0];
|
||||
break;
|
||||
case 8: // t matrix
|
||||
shift = 8 + (17 - scale);
|
||||
indtevtrans[0] = s * indcoord[1];
|
||||
indtevtrans[1] = t * indcoord[1];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
indtevtrans[0] = shift >= 0 ? indtevtrans[0] >> shift : indtevtrans[0] << -shift;
|
||||
indtevtrans[1] = shift >= 0 ? indtevtrans[1] >> shift : indtevtrans[1] << -shift;
|
||||
}
|
||||
|
||||
if (indirect.fb_addprev)
|
||||
{
|
||||
TexCoord.s += (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
|
||||
TexCoord.t += (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
TexCoord.s = (int)(WrapIndirectCoord(s, indirect.sw) + indtevtrans[0]);
|
||||
TexCoord.t = (int)(WrapIndirectCoord(t, indirect.tw) + indtevtrans[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::Draw()
|
||||
{
|
||||
_assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH);
|
||||
_assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT);
|
||||
|
||||
INCSTAT(swstats.thisFrame.tevPixelsIn);
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
|
||||
u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum);
|
||||
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
|
||||
|
||||
const TEXSCALE& texscale = bpmem.texscale[stageNum2];
|
||||
s32 scaleS = stageOdd ? texscale.ss1:texscale.ss0;
|
||||
s32 scaleT = stageOdd ? texscale.ts1:texscale.ts0;
|
||||
|
||||
TextureSampler::Sample(Uv[texcoordSel].s >> scaleS, Uv[texcoordSel].t >> scaleT,
|
||||
IndirectLod[stageNum], IndirectLinear[stageNum], texmap, IndirectTex[stageNum]);
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_SWVideoConfig.bDumpTevStages)
|
||||
{
|
||||
u8 stage[4] = { IndirectTex[stageNum][TextureSampler::ALP_SMP],
|
||||
IndirectTex[stageNum][TextureSampler::BLU_SMP],
|
||||
IndirectTex[stageNum][TextureSampler::GRN_SMP],
|
||||
255};
|
||||
DebugUtil::DrawTempBuffer(stage, INDIRECT + stageNum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
|
||||
{
|
||||
int stageNum2 = stageNum >> 1;
|
||||
int stageOdd = stageNum&1;
|
||||
TwoTevStageOrders &order = bpmem.tevorders[stageNum2];
|
||||
TevKSel &kSel = bpmem.tevksel[stageNum2];
|
||||
|
||||
// stage combiners
|
||||
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[stageNum].colorC;
|
||||
TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[stageNum].alphaC;
|
||||
|
||||
int texcoordSel = order.getTexCoord(stageOdd);
|
||||
int texmap = order.getTexMap(stageOdd);
|
||||
|
||||
Indirect(stageNum, Uv[texcoordSel].s, Uv[texcoordSel].t);
|
||||
|
||||
// sample texture
|
||||
if (order.getEnable(stageOdd))
|
||||
{
|
||||
// RGBA
|
||||
u8 texel[4];
|
||||
|
||||
TextureSampler::Sample(TexCoord.s, TexCoord.t, TextureLod[stageNum], TextureLinear[stageNum], texmap, texel);
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_SWVideoConfig.bDumpTevTextureFetches)
|
||||
DebugUtil::DrawTempBuffer(texel, DIRECT_TFETCH + stageNum);
|
||||
#endif
|
||||
|
||||
int swaptable = ac.tswap * 2;
|
||||
|
||||
TexColor[RED_C] = texel[bpmem.tevksel[swaptable].swap1];
|
||||
TexColor[GRN_C] = texel[bpmem.tevksel[swaptable].swap2];
|
||||
swaptable++;
|
||||
TexColor[BLU_C] = texel[bpmem.tevksel[swaptable].swap1];
|
||||
TexColor[ALP_C] = texel[bpmem.tevksel[swaptable].swap2];
|
||||
}
|
||||
|
||||
// set konst for this stage
|
||||
int kc = kSel.getKC(stageOdd);
|
||||
int ka = kSel.getKA(stageOdd);
|
||||
StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]);
|
||||
StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]);
|
||||
StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]);
|
||||
StageKonst[ALP_C] = *(m_KonstLUT[ka][ALP_C]);
|
||||
|
||||
// set color
|
||||
SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2);
|
||||
|
||||
// combine inputs
|
||||
if (cc.bias != 3)
|
||||
DrawColorRegular(cc);
|
||||
else
|
||||
DrawColorCompare(cc);
|
||||
|
||||
if (cc.clamp)
|
||||
{
|
||||
Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]);
|
||||
Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]);
|
||||
Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reg[cc.dest][RED_C] = Clamp1024(Reg[cc.dest][RED_C]);
|
||||
Reg[cc.dest][GRN_C] = Clamp1024(Reg[cc.dest][GRN_C]);
|
||||
Reg[cc.dest][BLU_C] = Clamp1024(Reg[cc.dest][BLU_C]);
|
||||
}
|
||||
|
||||
if (ac.bias != 3)
|
||||
DrawAlphaRegular(ac);
|
||||
else
|
||||
DrawAlphaCompare(ac);
|
||||
|
||||
if (ac.clamp)
|
||||
Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]);
|
||||
else
|
||||
Reg[ac.dest][ALP_C] = Clamp1024(Reg[ac.dest][ALP_C]);
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_SWVideoConfig.bDumpTevStages)
|
||||
{
|
||||
u8 stage[4] = {(u8)Reg[0][RED_C], (u8)Reg[0][GRN_C], (u8)Reg[0][BLU_C], (u8)Reg[0][ALP_C]};
|
||||
DebugUtil::DrawTempBuffer(stage, DIRECT + stageNum);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// convert to 8 bits per component
|
||||
// the results of the last tev stage are put onto the screen,
|
||||
// regardless of the used destination register - TODO: Verify!
|
||||
u32 color_index = bpmem.combiners[bpmem.genMode.numtevstages].colorC.dest;
|
||||
u32 alpha_index = bpmem.combiners[bpmem.genMode.numtevstages].alphaC.dest;
|
||||
u8 output[4] = {(u8)Reg[alpha_index][ALP_C], (u8)Reg[color_index][BLU_C], (u8)Reg[color_index][GRN_C], (u8)Reg[color_index][RED_C]};
|
||||
|
||||
if (!TevAlphaTest(output[ALP_C]))
|
||||
return;
|
||||
|
||||
// z texture
|
||||
if (bpmem.ztex2.op)
|
||||
{
|
||||
u32 ztex = bpmem.ztex1.bias;
|
||||
switch (bpmem.ztex2.type)
|
||||
{
|
||||
case 0: // 8 bit
|
||||
ztex += TexColor[ALP_C];
|
||||
break;
|
||||
case 1: // 16 bit
|
||||
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
|
||||
break;
|
||||
case 2: // 24 bit
|
||||
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
|
||||
break;
|
||||
}
|
||||
|
||||
if (bpmem.ztex2.op == ZTEXTURE_ADD)
|
||||
ztex += Position[2];
|
||||
|
||||
Position[2] = ztex & 0x00ffffff;
|
||||
}
|
||||
|
||||
// fog
|
||||
if (bpmem.fog.c_proj_fsel.fsel)
|
||||
{
|
||||
float ze;
|
||||
|
||||
if (bpmem.fog.c_proj_fsel.proj == 0)
|
||||
{
|
||||
// perspective
|
||||
// ze = A/(B - (Zs >> B_SHF))
|
||||
s32 denom = bpmem.fog.b_magnitude - (Position[2] >> bpmem.fog.b_shift);
|
||||
//in addition downscale magnitude and zs to 0.24 bits
|
||||
ze = (bpmem.fog.a.GetA() * 16777215.0f) / (float)denom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// orthographic
|
||||
// ze = a*Zs
|
||||
//in addition downscale zs to 0.24 bits
|
||||
ze = bpmem.fog.a.GetA() * ((float)Position[2] / 16777215.0f);
|
||||
|
||||
}
|
||||
|
||||
if(bpmem.fogRange.Base.Enabled)
|
||||
{
|
||||
// TODO: This is untested and should definitely be checked against real hw.
|
||||
// - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else
|
||||
// - scaling of the "k" coefficient isn't clear either.
|
||||
|
||||
// First, calculate the offset from the viewport center (normalized to 0..1)
|
||||
float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)swxfregs.viewport.wd;
|
||||
// Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value.
|
||||
int index = (int) (9 - std::abs(offset) * 9.f);
|
||||
index = (index < 0) ? 0 : (index > 9) ? 9 : index; // TODO: Shouldn't be necessary!
|
||||
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor)
|
||||
float k = bpmem.fogRange.K[index/2].GetValue(index%2) * 4.f;
|
||||
float x_adjust = sqrt(offset*offset + k*k)/k;
|
||||
ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
|
||||
}
|
||||
|
||||
ze -= bpmem.fog.c_proj_fsel.GetC();
|
||||
|
||||
// clamp 0 to 1
|
||||
float fog = (ze<0.0f) ? 0.0f : ((ze>1.0f) ? 1.0f : ze);
|
||||
|
||||
switch (bpmem.fog.c_proj_fsel.fsel)
|
||||
{
|
||||
case 4: // exp
|
||||
fog = 1.0f - pow(2.0f, -8.0f * fog);
|
||||
break;
|
||||
case 5: // exp2
|
||||
fog = 1.0f - pow(2.0f, -8.0f * fog * fog);
|
||||
break;
|
||||
case 6: // backward exp
|
||||
fog = 1.0f - fog;
|
||||
fog = pow(2.0f, -8.0f * fog);
|
||||
break;
|
||||
case 7: // backward exp2
|
||||
fog = 1.0f - fog;
|
||||
fog = pow(2.0f, -8.0f * fog * fog);
|
||||
break;
|
||||
}
|
||||
|
||||
// lerp from output to fog color
|
||||
u32 fogInt = (u32)(fog * 256);
|
||||
u32 invFog = 256 - fogInt;
|
||||
|
||||
output[RED_C] = (output[RED_C] * invFog + fogInt * bpmem.fog.color.r) >> 8;
|
||||
output[GRN_C] = (output[GRN_C] * invFog + fogInt * bpmem.fog.color.g) >> 8;
|
||||
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
|
||||
}
|
||||
|
||||
bool late_ztest = !bpmem.zcontrol.early_ztest || !g_SWVideoConfig.bZComploc;
|
||||
if (late_ztest && bpmem.zmode.testenable)
|
||||
{
|
||||
// TODO: Check against hw if these values get incremented even if depth testing is disabled
|
||||
SWPixelEngine::pereg.IncZInputQuadCount(false);
|
||||
|
||||
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
|
||||
return;
|
||||
|
||||
SWPixelEngine::pereg.IncZOutputQuadCount(false);
|
||||
}
|
||||
|
||||
#if ALLOW_TEV_DUMPS
|
||||
if (g_SWVideoConfig.bDumpTevStages)
|
||||
{
|
||||
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], INDIRECT, i, "Indirect");
|
||||
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT, i, "Stage");
|
||||
}
|
||||
|
||||
if (g_SWVideoConfig.bDumpTevTextureFetches)
|
||||
{
|
||||
for (u32 i = 0; i <= bpmem.genMode.numtevstages; ++i)
|
||||
{
|
||||
TwoTevStageOrders &order = bpmem.tevorders[i >> 1];
|
||||
if (order.getEnable(i & 1))
|
||||
DebugUtil::CopyTempBuffer(Position[0], Position[1], DIRECT_TFETCH, i, "TFetch");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
INCSTAT(swstats.thisFrame.tevPixelsOut);
|
||||
SWPixelEngine::pereg.IncBlendInputQuadCount();
|
||||
|
||||
EfbInterface::BlendTev(Position[0], Position[1], output);
|
||||
}
|
||||
|
||||
void Tev::SetRegColor(int reg, int comp, bool konst, s16 color)
|
||||
{
|
||||
if (konst)
|
||||
{
|
||||
KonstantColors[reg][comp] = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
Reg[reg][comp] = color;
|
||||
}
|
||||
}
|
||||
|
||||
void Tev::DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoArray(Reg, sizeof(Reg));
|
||||
|
||||
p.DoArray(KonstantColors, sizeof(KonstantColors));
|
||||
p.DoArray(TexColor,4);
|
||||
p.DoArray(RasColor,4);
|
||||
p.DoArray(StageKonst,4);
|
||||
p.DoArray(Zero16,4);
|
||||
|
||||
p.DoArray(FixedConstants,9);
|
||||
p.Do(AlphaBump);
|
||||
p.DoArray(IndirectTex, sizeof(IndirectTex));
|
||||
p.Do(TexCoord);
|
||||
|
||||
p.DoArray(m_BiasLUT,4);
|
||||
p.DoArray(m_ScaleLShiftLUT,4);
|
||||
p.DoArray(m_ScaleRShiftLUT,4);
|
||||
|
||||
p.DoArray(Position,3);
|
||||
p.DoArray(Color, sizeof(Color));
|
||||
p.DoArray(Uv, 8);
|
||||
p.DoArray(IndirectLod,4);
|
||||
p.DoArray(IndirectLinear,4);
|
||||
p.DoArray(TextureLod,16);
|
||||
p.DoArray(TextureLinear,16);
|
||||
}
|
91
Source/Core/VideoBackends/Software/Src/Tev.h
Normal file
91
Source/Core/VideoBackends/Software/Src/Tev.h
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TEV_H_
|
||||
#define _TEV_H_
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class Tev
|
||||
{
|
||||
struct InputRegType
|
||||
{
|
||||
unsigned a : 8;
|
||||
unsigned b : 8;
|
||||
unsigned c : 8;
|
||||
signed d : 11;
|
||||
};
|
||||
|
||||
struct TextureCoordinateType
|
||||
{
|
||||
signed s : 24;
|
||||
signed t : 24;
|
||||
};
|
||||
|
||||
// color order: ABGR
|
||||
s16 Reg[4][4];
|
||||
s16 KonstantColors[4][4];
|
||||
s16 TexColor[4];
|
||||
s16 RasColor[4];
|
||||
s16 StageKonst[4];
|
||||
s16 Zero16[4];
|
||||
|
||||
s16 FixedConstants[9];
|
||||
u8 AlphaBump;
|
||||
u8 IndirectTex[4][4];
|
||||
TextureCoordinateType TexCoord;
|
||||
|
||||
s16 *m_ColorInputLUT[16][3];
|
||||
s16 *m_AlphaInputLUT[8]; // values must point to ABGR color
|
||||
s16 *m_KonstLUT[32][4];
|
||||
s16 m_BiasLUT[4];
|
||||
u8 m_ScaleLShiftLUT[4];
|
||||
u8 m_ScaleRShiftLUT[4];
|
||||
|
||||
// enumeration for color input LUT
|
||||
enum
|
||||
{
|
||||
BLU_INP,
|
||||
GRN_INP,
|
||||
RED_INP
|
||||
};
|
||||
|
||||
enum BufferBase
|
||||
{
|
||||
DIRECT = 0,
|
||||
DIRECT_TFETCH = 16,
|
||||
INDIRECT = 32
|
||||
};
|
||||
|
||||
void SetRasColor(int colorChan, int swaptable);
|
||||
|
||||
void DrawColorRegular(TevStageCombiner::ColorCombiner &cc);
|
||||
void DrawColorCompare(TevStageCombiner::ColorCombiner &cc);
|
||||
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac);
|
||||
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac);
|
||||
|
||||
void Indirect(unsigned int stageNum, s32 s, s32 t);
|
||||
|
||||
public:
|
||||
s32 Position[3];
|
||||
u8 Color[2][4]; // must be RGBA for correct swap table ordering
|
||||
TextureCoordinateType Uv[8];
|
||||
s32 IndirectLod[4];
|
||||
bool IndirectLinear[4];
|
||||
s32 TextureLod[16];
|
||||
bool TextureLinear[16];
|
||||
|
||||
void Init();
|
||||
|
||||
void Draw();
|
||||
|
||||
void SetRegColor(int reg, int comp, bool konst, s16 color);
|
||||
|
||||
enum { ALP_C, BLU_C, GRN_C, RED_C };
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
};
|
||||
|
||||
#endif
|
1435
Source/Core/VideoBackends/Software/Src/TextureEncoder.cpp
Normal file
1435
Source/Core/VideoBackends/Software/Src/TextureEncoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
15
Source/Core/VideoBackends/Software/Src/TextureEncoder.h
Normal file
15
Source/Core/VideoBackends/Software/Src/TextureEncoder.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _OPCODEDECODER_H_
|
||||
#define _OPCODEDECODER_H_
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace TextureEncoder
|
||||
{
|
||||
void Encode(u8 *dest_ptr);
|
||||
}
|
||||
|
||||
#endif
|
233
Source/Core/VideoBackends/Software/Src/TextureSampler.cpp
Normal file
233
Source/Core/VideoBackends/Software/Src/TextureSampler.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "TextureSampler.h"
|
||||
|
||||
#include "BPMemLoader.h"
|
||||
#include "TextureDecoder.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define ALLOW_MIPMAP 1
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
|
||||
inline void WrapCoord(int &coord, int wrapMode, int imageSize)
|
||||
{
|
||||
switch (wrapMode)
|
||||
{
|
||||
case 0: // clamp
|
||||
coord = (coord>imageSize)?imageSize:(coord<0)?0:coord;
|
||||
break;
|
||||
case 1: // wrap
|
||||
coord = coord % (imageSize + 1);
|
||||
coord = (coord<0)?imageSize+coord:coord;
|
||||
break;
|
||||
case 2: // mirror
|
||||
{
|
||||
int sizePlus1 = imageSize + 1;
|
||||
int div = coord / sizePlus1;
|
||||
coord = coord - (div * sizePlus1);
|
||||
coord = (coord<0)?-coord:coord;
|
||||
coord = (div&1)?imageSize - coord:coord;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
||||
{
|
||||
outTexel[0] = inTexel[0] * fract;
|
||||
outTexel[1] = inTexel[1] * fract;
|
||||
outTexel[2] = inTexel[2] * fract;
|
||||
outTexel[3] = inTexel[3] * fract;
|
||||
}
|
||||
|
||||
inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
||||
{
|
||||
outTexel[0] += inTexel[0] * fract;
|
||||
outTexel[1] += inTexel[1] * fract;
|
||||
outTexel[2] += inTexel[2] * fract;
|
||||
outTexel[3] += inTexel[3] * fract;
|
||||
}
|
||||
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
|
||||
{
|
||||
int baseMip = 0;
|
||||
bool mipLinear = false;
|
||||
|
||||
#if (ALLOW_MIPMAP)
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
|
||||
|
||||
s32 lodFract = lod & 0xf;
|
||||
|
||||
if (lod > 0 && tm0.min_filter & 3)
|
||||
{
|
||||
// use mipmap
|
||||
baseMip = lod >> 4;
|
||||
mipLinear = (lodFract && tm0.min_filter & 2);
|
||||
|
||||
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
|
||||
baseMip += (lodFract >> 3) & (tm0.min_filter & 1);
|
||||
}
|
||||
|
||||
if (mipLinear)
|
||||
{
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
|
||||
SampleMip(s, t, baseMip, linear, texmap, sampledTex);
|
||||
SetTexel(sampledTex, texel, (16 - lodFract));
|
||||
|
||||
SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex);
|
||||
AddTexel(sampledTex, texel, lodFract);
|
||||
|
||||
sample[0] = (u8)(texel[0] >> 4);
|
||||
sample[1] = (u8)(texel[1] >> 4);
|
||||
sample[2] = (u8)(texel[2] >> 4);
|
||||
sample[3] = (u8)(texel[3] >> 4);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SampleMip(s, t, baseMip, linear, texmap, sample);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample)
|
||||
{
|
||||
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
||||
u8 subTexmap = texmap & 3;
|
||||
|
||||
TexMode0& tm0 = texUnit.texMode0[subTexmap];
|
||||
TexImage0& ti0 = texUnit.texImage0[subTexmap];
|
||||
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
|
||||
|
||||
u8 *imageSrc, *imageSrcOdd = NULL;
|
||||
if (texUnit.texImage1[subTexmap].image_type)
|
||||
{
|
||||
imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE];
|
||||
if (ti0.format == GX_TF_RGBA8)
|
||||
imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
|
||||
imageSrc = Memory::GetPointer(imageBase);
|
||||
}
|
||||
|
||||
int imageWidth = ti0.width;
|
||||
int imageHeight = ti0.height;
|
||||
|
||||
int tlutAddress = texTlut.tmem_offset << 9;
|
||||
|
||||
// reduce sample location and texture size to mip level
|
||||
// move texture pointer to mip location
|
||||
if (mip)
|
||||
{
|
||||
int mipWidth = imageWidth + 1;
|
||||
int mipHeight = imageHeight + 1;
|
||||
|
||||
int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format);
|
||||
int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format);
|
||||
int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format);
|
||||
|
||||
imageWidth >>= mip;
|
||||
imageHeight >>= mip;
|
||||
s >>= mip;
|
||||
t >>= mip;
|
||||
|
||||
while (mip)
|
||||
{
|
||||
mipWidth = max(mipWidth, fmtWidth);
|
||||
mipHeight = max(mipHeight, fmtHeight);
|
||||
u32 size = (mipWidth * mipHeight * fmtDepth) >> 1;
|
||||
|
||||
imageSrc += size;
|
||||
mipWidth >>= 1;
|
||||
mipHeight >>= 1;
|
||||
mip--;
|
||||
}
|
||||
}
|
||||
|
||||
if (linear)
|
||||
{
|
||||
// offset linear sampling
|
||||
s -= 64;
|
||||
t -= 64;
|
||||
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
|
||||
// linear sampling
|
||||
int imageSPlus1 = imageS + 1;
|
||||
int fractS = s & 0x7f;
|
||||
|
||||
int imageTPlus1 = imageT + 1;
|
||||
int fractT = t & 0x7f;
|
||||
|
||||
u8 sampledTex[4];
|
||||
u32 texel[4];
|
||||
|
||||
WrapCoord(imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(imageT, tm0.wrap_t, imageHeight);
|
||||
WrapCoord(imageSPlus1, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(imageTPlus1, tm0.wrap_t, imageHeight);
|
||||
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
{
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
|
||||
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
else
|
||||
{
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT, imageWidth);
|
||||
SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT, imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (128 - fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1, imageWidth);
|
||||
AddTexel(sampledTex, texel, (128 - fractS) * (fractT));
|
||||
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageTPlus1, imageWidth);
|
||||
AddTexel(sampledTex, texel, (fractS) * (fractT));
|
||||
}
|
||||
|
||||
sample[0] = (u8)(texel[0] >> 14);
|
||||
sample[1] = (u8)(texel[1] >> 14);
|
||||
sample[2] = (u8)(texel[2] >> 14);
|
||||
sample[3] = (u8)(texel[3] >> 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
// integer part of sample location
|
||||
int imageS = s >> 7;
|
||||
int imageT = t >> 7;
|
||||
|
||||
// nearest neighbor sampling
|
||||
WrapCoord(imageS, tm0.wrap_s, imageWidth);
|
||||
WrapCoord(imageT, tm0.wrap_t, imageHeight);
|
||||
|
||||
if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type))
|
||||
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlutAddress, texTlut.tlut_format);
|
||||
else
|
||||
TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, imageWidth);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
21
Source/Core/VideoBackends/Software/Src/TextureSampler.h
Normal file
21
Source/Core/VideoBackends/Software/Src/TextureSampler.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TEXTURESAMPLER_H_
|
||||
#define _TEXTURESAMPLER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
namespace TextureSampler
|
||||
{
|
||||
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample);
|
||||
|
||||
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample);
|
||||
|
||||
enum { RED_SMP, GRN_SMP, BLU_SMP, ALP_SMP };
|
||||
}
|
||||
|
||||
|
||||
#endif
|
513
Source/Core/VideoBackends/Software/Src/TransformUnit.cpp
Normal file
513
Source/Core/VideoBackends/Software/Src/TransformUnit.cpp
Normal file
@ -0,0 +1,513 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "TransformUnit.h"
|
||||
#include "XFMemLoader.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "BPMemLoader.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
|
||||
#include "Vec3.h"
|
||||
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
|
||||
void MultiplyVec2Mat24(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = 1.0f;
|
||||
}
|
||||
|
||||
void MultiplyVec2Mat34(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] + mat[11];
|
||||
}
|
||||
|
||||
void MultiplyVec3Mat33(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z;
|
||||
result.y = mat[3] * vec.x + mat[4] * vec.y + mat[5] * vec.z;
|
||||
result.z = mat[6] * vec.x + mat[7] * vec.y + mat[8] * vec.z;
|
||||
}
|
||||
|
||||
void MultiplyVec3Mat24(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = 1.0f;
|
||||
}
|
||||
|
||||
void MultiplyVec3Mat34(const Vec3 &vec, const float *mat, Vec3 &result)
|
||||
{
|
||||
result.x = mat[0] * vec.x + mat[1] * vec.y + mat[2] * vec.z + mat[3];
|
||||
result.y = mat[4] * vec.x + mat[5] * vec.y + mat[6] * vec.z + mat[7];
|
||||
result.z = mat[8] * vec.x + mat[9] * vec.y + mat[10] * vec.z + mat[11];
|
||||
}
|
||||
|
||||
void MultipleVec3Perspective(const Vec3 &vec, const float *proj, Vec4 &result)
|
||||
{
|
||||
result.x = proj[0] * vec.x + proj[1] * vec.z;
|
||||
result.y = proj[2] * vec.y + proj[3] * vec.z;
|
||||
//result.z = (proj[4] * vec.z + proj[5]);
|
||||
result.z = (proj[4] * vec.z + proj[5]) * (1.0f - (float)1e-7);
|
||||
result.w = -vec.z;
|
||||
}
|
||||
|
||||
void MultipleVec3Ortho(const Vec3 &vec, const float *proj, Vec4 &result)
|
||||
{
|
||||
result.x = proj[0] * vec.x + proj[1];
|
||||
result.y = proj[2] * vec.y + proj[3];
|
||||
result.z = proj[4] * vec.z + proj[5];
|
||||
result.w = 1;
|
||||
}
|
||||
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst)
|
||||
{
|
||||
const float* mat = (const float*)&swxfregs.posMatrices[src->posMtx * 4];
|
||||
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
|
||||
|
||||
if (swxfregs.projection.type == GX_PERSPECTIVE)
|
||||
{
|
||||
MultipleVec3Perspective(dst->mvPosition, swxfregs.projection.rawProjection, dst->projectedPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
MultipleVec3Ortho(dst->mvPosition, swxfregs.projection.rawProjection, dst->projectedPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst)
|
||||
{
|
||||
const float* mat = (const float*)&swxfregs.normalMatrices[(src->posMtx & 31) * 3];
|
||||
|
||||
if (nbt)
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]);
|
||||
MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]);
|
||||
dst->normal[0].normalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
|
||||
dst->normal[0].normalize();
|
||||
}
|
||||
}
|
||||
|
||||
void TransformTexCoordRegular(const TexMtxInfo &texinfo, int coordNum, bool specialCase, const InputVertexData *srcVertex, OutputVertexData *dstVertex)
|
||||
{
|
||||
const Vec3 *src;
|
||||
switch (texinfo.sourcerow)
|
||||
{
|
||||
case XF_SRCGEOM_INROW:
|
||||
src = &srcVertex->position;
|
||||
break;
|
||||
case XF_SRCNORMAL_INROW:
|
||||
src = &srcVertex->normal[0];
|
||||
break;
|
||||
case XF_SRCBINORMAL_T_INROW:
|
||||
src = &srcVertex->normal[1];
|
||||
break;
|
||||
case XF_SRCBINORMAL_B_INROW:
|
||||
src = &srcVertex->normal[2];
|
||||
break;
|
||||
default:
|
||||
_assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
|
||||
src = (Vec3*)srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW];
|
||||
break;
|
||||
}
|
||||
|
||||
const float *mat = (const float*)&swxfregs.posMatrices[srcVertex->texMtx[coordNum] * 4];
|
||||
Vec3 *dst = &dstVertex->texCoords[coordNum];
|
||||
|
||||
if (texinfo.projection == XF_TEXPROJ_ST)
|
||||
{
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11 || specialCase)
|
||||
MultiplyVec2Mat24(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat24(*src, mat, *dst);
|
||||
}
|
||||
else // texinfo.projection == XF_TEXPROJ_STQ
|
||||
{
|
||||
_assert_(!specialCase);
|
||||
|
||||
if (texinfo.inputform == XF_TEXINPUT_AB11)
|
||||
MultiplyVec2Mat34(*src, mat, *dst);
|
||||
else
|
||||
MultiplyVec3Mat34(*src, mat, *dst);
|
||||
}
|
||||
|
||||
if (swxfregs.dualTexTrans)
|
||||
{
|
||||
Vec3 tempCoord;
|
||||
|
||||
// normalize
|
||||
const PostMtxInfo &postInfo = swxfregs.postMtxInfo[coordNum];
|
||||
const float *postMat = (const float*)&swxfregs.postMatrices[postInfo.index * 4];
|
||||
|
||||
if (specialCase)
|
||||
{
|
||||
// no normalization
|
||||
// q of input is 1
|
||||
// q of output is unknown
|
||||
tempCoord.x = dst->x;
|
||||
tempCoord.y = dst->y;
|
||||
|
||||
dst->x = postMat[0] * tempCoord.x + postMat[1] * tempCoord.y + postMat[2] + postMat[3];
|
||||
dst->y = postMat[4] * tempCoord.x + postMat[5] * tempCoord.y + postMat[6] + postMat[7];
|
||||
dst->z = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (postInfo.normalize)
|
||||
tempCoord = dst->normalized();
|
||||
else
|
||||
tempCoord = *dst;
|
||||
|
||||
MultiplyVec3Mat34(tempCoord, postMat, *dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LightPointer
|
||||
{
|
||||
u32 reserved[3];
|
||||
u8 color[4];
|
||||
Vec3 cosatt;
|
||||
Vec3 distatt;
|
||||
Vec3 pos;
|
||||
Vec3 dir;
|
||||
};
|
||||
|
||||
inline void AddIntegerColor(const u8 *src, Vec3 &dst)
|
||||
{
|
||||
dst.x += src[1];
|
||||
dst.y += src[2];
|
||||
dst.z += src[3];
|
||||
}
|
||||
|
||||
inline void AddScaledIntegerColor(const u8 *src, float scale, Vec3 &dst)
|
||||
{
|
||||
dst.x += src[1] * scale;
|
||||
dst.y += src[2] * scale;
|
||||
dst.z += src[3] * scale;
|
||||
}
|
||||
|
||||
inline float Clamp(float val, float a, float b)
|
||||
{
|
||||
return val<a?a:val>b?b:val;
|
||||
}
|
||||
|
||||
inline float SafeDivide(float n, float d)
|
||||
{
|
||||
return (d==0) ? (n>0?1:0) : n/d;
|
||||
}
|
||||
|
||||
void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const LitChannel &chan, Vec3 &lightCol)
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&swxfregs.lights[0x10*lightNum];
|
||||
|
||||
if (!(chan.attnfunc & 1))
|
||||
{
|
||||
// atten disabled
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
AddIntegerColor(light->color, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
Vec3 ldir = (light->pos - pos).normalized();
|
||||
float diffuse = ldir * normal;
|
||||
AddScaledIntegerColor(light->color, diffuse, lightCol);
|
||||
}
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
Vec3 ldir = (light->pos - pos).normalized();
|
||||
float diffuse = max(0.0f, ldir * normal);
|
||||
AddScaledIntegerColor(light->color, diffuse, lightCol);
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else // spec and spot
|
||||
{
|
||||
// not sure about divide by zero checks
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn;
|
||||
|
||||
if (chan.attnfunc == 3) // spot
|
||||
{
|
||||
float dist2 = ldir.length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = max(0.0f, ldir * light->dir);
|
||||
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = SafeDivide(max(0.0f, cosAtt), distAtt);
|
||||
}
|
||||
else if (chan.attnfunc == 1) // specular
|
||||
{
|
||||
// donko - what is going on here? 655.36 is a guess but seems about right.
|
||||
attn = (light->pos * normal) > -655.36 ? max(0.0f, (light->dir * normal)) : 0;
|
||||
ldir.set(1.0f, attn, attn * attn);
|
||||
|
||||
float cosAtt = max(0.0f, light->cosatt * ldir);
|
||||
float distAtt = light->distatt * ldir;
|
||||
attn = SafeDivide(max(0.0f, cosAtt), distAtt);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("LightColor");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
AddScaledIntegerColor(light->color, attn, lightCol);
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
float difAttn = ldir * normal;
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
}
|
||||
break;
|
||||
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
float difAttn = max(0.0f, ldir * normal);
|
||||
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const LitChannel &chan, float &lightCol)
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&swxfregs.lights[0x10*lightNum];
|
||||
|
||||
if (!(chan.attnfunc & 1))
|
||||
{
|
||||
// atten disabled
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0];
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
Vec3 ldir = (light->pos - pos).normalized();
|
||||
float diffuse = ldir * normal;
|
||||
lightCol += light->color[0] * diffuse;
|
||||
}
|
||||
break;
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
Vec3 ldir = (light->pos - pos).normalized();
|
||||
float diffuse = max(0.0f, ldir * normal);
|
||||
lightCol += light->color[0] * diffuse;
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
else // spec and spot
|
||||
{
|
||||
Vec3 ldir = light->pos - pos;
|
||||
float attn;
|
||||
|
||||
if (chan.attnfunc == 3) // spot
|
||||
{
|
||||
float dist2 = ldir.length2();
|
||||
float dist = sqrtf(dist2);
|
||||
ldir = ldir / dist;
|
||||
attn = max(0.0f, ldir * light->dir);
|
||||
|
||||
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
|
||||
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
|
||||
attn = SafeDivide(max(0.0f, cosAtt), distAtt);
|
||||
}
|
||||
else /* if (chan.attnfunc == 1) */ // specular
|
||||
{
|
||||
// donko - what is going on here? 655.36 is a guess but seems about right.
|
||||
attn = (light->pos * normal) > -655.36 ? max(0.0f, (light->dir * normal)) : 0;
|
||||
ldir.set(1.0f, attn, attn * attn);
|
||||
|
||||
float cosAtt = light->cosatt * ldir;
|
||||
float distAtt = light->distatt * ldir;
|
||||
attn = SafeDivide(max(0.0f, cosAtt), distAtt);
|
||||
}
|
||||
|
||||
switch (chan.diffusefunc)
|
||||
{
|
||||
case LIGHTDIF_NONE:
|
||||
lightCol += light->color[0] * attn;
|
||||
break;
|
||||
case LIGHTDIF_SIGN:
|
||||
{
|
||||
float difAttn = ldir * normal;
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
}
|
||||
break;
|
||||
|
||||
case LIGHTDIF_CLAMP:
|
||||
{
|
||||
float difAttn = max(0.0f, ldir * normal);
|
||||
lightCol += light->color[0] * attn * difAttn;
|
||||
}
|
||||
break;
|
||||
default: _assert_(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst)
|
||||
{
|
||||
for (u32 chan = 0; chan < swxfregs.nNumChans; chan++)
|
||||
{
|
||||
// abgr
|
||||
u8 matcolor[4];
|
||||
u8 chancolor[4];
|
||||
|
||||
// color
|
||||
LitChannel &colorchan = swxfregs.color[chan];
|
||||
if (colorchan.matsource)
|
||||
*(u32*)matcolor = *(u32*)src->color[chan]; // vertex
|
||||
else
|
||||
*(u32*)matcolor = swxfregs.matColor[chan];
|
||||
|
||||
if (colorchan.enablelighting)
|
||||
{
|
||||
Vec3 lightCol;
|
||||
if (colorchan.ambsource)
|
||||
{
|
||||
// vertex
|
||||
lightCol.x = src->color[chan][1];
|
||||
lightCol.y = src->color[chan][2];
|
||||
lightCol.z = src->color[chan][3];
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *ambColor = (u8*)&swxfregs.ambColor[chan];
|
||||
lightCol.x = ambColor[1];
|
||||
lightCol.y = ambColor[2];
|
||||
lightCol.z = ambColor[3];
|
||||
}
|
||||
|
||||
u8 mask = colorchan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask&(1<<i))
|
||||
LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol);
|
||||
}
|
||||
|
||||
float inv = 1.0f / 255.0f;
|
||||
chancolor[1] = (u8)(matcolor[1] * Clamp(lightCol.x * inv, 0.0f, 1.0f));
|
||||
chancolor[2] = (u8)(matcolor[2] * Clamp(lightCol.y * inv, 0.0f, 1.0f));
|
||||
chancolor[3] = (u8)(matcolor[3] * Clamp(lightCol.z * inv, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
*(u32*)chancolor = *(u32*)matcolor;
|
||||
}
|
||||
|
||||
// alpha
|
||||
LitChannel &alphachan = swxfregs.alpha[chan];
|
||||
if (alphachan.matsource)
|
||||
matcolor[0] = src->color[chan][0]; // vertex
|
||||
else
|
||||
matcolor[0] = swxfregs.matColor[chan] & 0xff;
|
||||
|
||||
if (swxfregs.alpha[chan].enablelighting)
|
||||
{
|
||||
float lightCol;
|
||||
if (alphachan.ambsource)
|
||||
lightCol = src->color[chan][0]; // vertex
|
||||
else
|
||||
lightCol = (float)(swxfregs.ambColor[chan] & 0xff);
|
||||
|
||||
u8 mask = alphachan.GetFullLightMask();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
if (mask&(1<<i))
|
||||
LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol);
|
||||
}
|
||||
|
||||
chancolor[0] = (u8)(matcolor[0] * Clamp(lightCol / 255.0f, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
chancolor[0] = matcolor[0];
|
||||
}
|
||||
|
||||
// abgr -> rgba
|
||||
*(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase)
|
||||
{
|
||||
for (u32 coordNum = 0; coordNum < swxfregs.numTexGens; coordNum++)
|
||||
{
|
||||
const TexMtxInfo &texinfo = swxfregs.texMtxInfo[coordNum];
|
||||
|
||||
switch (texinfo.texgentype)
|
||||
{
|
||||
case XF_TEXGEN_REGULAR:
|
||||
TransformTexCoordRegular(texinfo, coordNum, specialCase, src, dst);
|
||||
break;
|
||||
case XF_TEXGEN_EMBOSS_MAP:
|
||||
{
|
||||
const LightPointer *light = (const LightPointer*)&swxfregs.lights[0x10*texinfo.embosslightshift];
|
||||
|
||||
Vec3 ldir = (light->pos - dst->mvPosition).normalized();
|
||||
float d1 = ldir * dst->normal[1];
|
||||
float d2 = ldir * dst->normal[2];
|
||||
|
||||
dst->texCoords[coordNum].x = dst->texCoords[texinfo.embosssourceshift].x + d1;
|
||||
dst->texCoords[coordNum].y = dst->texCoords[texinfo.embosssourceshift].y + d2;
|
||||
dst->texCoords[coordNum].z = dst->texCoords[texinfo.embosssourceshift].z;
|
||||
}
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC0:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[0][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[0][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
case XF_TEXGEN_COLOR_STRGBC1:
|
||||
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
|
||||
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
|
||||
dst->texCoords[coordNum].x = (float)dst->color[1][0] / 255.0f;
|
||||
dst->texCoords[coordNum].y = (float)dst->color[1][1] / 255.0f;
|
||||
dst->texCoords[coordNum].z = 1.0f;
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 coordNum = 0; coordNum < swxfregs.numTexGens; coordNum++)
|
||||
{
|
||||
dst->texCoords[coordNum][0] *= (bpmem.texcoords[coordNum].s.scale_minus_1 + 1);
|
||||
dst->texCoords[coordNum][1] *= (bpmem.texcoords[coordNum].t.scale_minus_1 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
Source/Core/VideoBackends/Software/Src/TransformUnit.h
Normal file
24
Source/Core/VideoBackends/Software/Src/TransformUnit.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TRANSFORM_UNIT_H_
|
||||
#define _TRANSFORM_UNIT_H_
|
||||
|
||||
struct InputVertexData;
|
||||
struct OutputVertexData;
|
||||
|
||||
namespace TransformUnit
|
||||
{
|
||||
void MultiplyVec2Mat24(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec2Mat34(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec3Mat33(const float *vec, const float *mat, float *result);
|
||||
void MultiplyVec3Mat34(const float *vec, const float *mat, float *result);
|
||||
|
||||
void TransformPosition(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst);
|
||||
void TransformColor(const InputVertexData *src, OutputVertexData *dst);
|
||||
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst, bool specialCase);
|
||||
}
|
||||
|
||||
#endif
|
110
Source/Core/VideoBackends/Software/Src/Vec3.h
Normal file
110
Source/Core/VideoBackends/Software/Src/Vec3.h
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VEC3_H
|
||||
#define _VEC3_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "ChunkFile.h"
|
||||
|
||||
class Vec3
|
||||
{
|
||||
public:
|
||||
float x,y,z;
|
||||
Vec3() { }
|
||||
explicit Vec3(float f) {x=y=z=f;}
|
||||
explicit Vec3(const float *f) {x=f[0]; y=f[1]; z=f[2];}
|
||||
Vec3(const float _x, const float _y, const float _z) {
|
||||
x=_x; y=_y; z=_z;
|
||||
}
|
||||
void set(const float _x, const float _y, const float _z) {
|
||||
x=_x; y=_y; z=_z;
|
||||
}
|
||||
Vec3 operator + (const Vec3 &other) const {
|
||||
return Vec3(x+other.x, y+other.y, z+other.z);
|
||||
}
|
||||
void operator += (const Vec3 &other) {
|
||||
x+=other.x; y+=other.y; z+=other.z;
|
||||
}
|
||||
Vec3 operator -(const Vec3 &v) const {
|
||||
return Vec3(x-v.x,y-v.y,z-v.z);
|
||||
}
|
||||
void operator -= (const Vec3 &other)
|
||||
{
|
||||
x-=other.x; y-=other.y; z-=other.z;
|
||||
}
|
||||
Vec3 operator -() const {
|
||||
return Vec3(-x,-y,-z);
|
||||
}
|
||||
|
||||
Vec3 operator * (const float f) const {
|
||||
return Vec3(x*f,y*f,z*f);
|
||||
}
|
||||
Vec3 operator / (const float f) const {
|
||||
float invf = (1.0f/f);
|
||||
return Vec3(x*invf,y*invf,z*invf);
|
||||
}
|
||||
void operator /= (const float f)
|
||||
{
|
||||
*this = *this / f;
|
||||
}
|
||||
float operator * (const Vec3 &other) const {
|
||||
return x*other.x + y*other.y + z*other.z;
|
||||
}
|
||||
void operator *= (const float f) {
|
||||
*this = *this * f;
|
||||
}
|
||||
Vec3 scaled_by(const Vec3 &other) const {
|
||||
return Vec3(x*other.x, y*other.y, z*other.z);
|
||||
}
|
||||
|
||||
Vec3 operator %(const Vec3 &v) const {
|
||||
return Vec3(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);
|
||||
}
|
||||
float length2() const {
|
||||
return x*x+y*y+z*z;
|
||||
}
|
||||
float length() const {
|
||||
return sqrtf(length2());
|
||||
}
|
||||
float distance2_to(Vec3 &other)
|
||||
{
|
||||
return (other-(*this)).length2();
|
||||
}
|
||||
Vec3 normalized() const {
|
||||
return (*this) / length();
|
||||
|
||||
}
|
||||
void normalize() {
|
||||
(*this) /= length();
|
||||
}
|
||||
float &operator [] (int i)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
float operator [] (const int i) const
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
bool operator == (const Vec3 &other) const
|
||||
{
|
||||
if (x==other.x && y==other.y && z==other.z)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
void setZero()
|
||||
{
|
||||
memset((void *)this,0,sizeof(float)*3);
|
||||
}
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(x);
|
||||
p.Do(y);
|
||||
p.Do(z);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
67
Source/Core/VideoBackends/Software/Src/VideoBackend.h
Normal file
67
Source/Core/VideoBackends/Software/Src/VideoBackend.h
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
#ifndef SW_VIDEO_BACKEND_H_
|
||||
#define SW_VIDEO_BACKEND_H_
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
namespace SW
|
||||
{
|
||||
|
||||
class VideoSoftware : public VideoBackend
|
||||
{
|
||||
bool Initialize(void *&);
|
||||
void Shutdown();
|
||||
|
||||
std::string GetName();
|
||||
|
||||
void EmuStateChange(EMUSTATE_CHANGE newState);
|
||||
|
||||
void RunLoop(bool enable);
|
||||
|
||||
void ShowConfig(void* parent);
|
||||
|
||||
void Video_Prepare();
|
||||
void Video_Cleanup();
|
||||
|
||||
void Video_EnterLoop();
|
||||
void Video_ExitLoop();
|
||||
void Video_BeginField(u32, u32, u32);
|
||||
void Video_EndField();
|
||||
|
||||
u32 Video_AccessEFB(EFBAccessType, u32, u32, u32);
|
||||
u32 Video_GetQueryResult(PerfQueryType type);
|
||||
|
||||
void Video_AddMessage(const char* pstr, unsigned int milliseconds);
|
||||
void Video_ClearMessages();
|
||||
bool Video_Screenshot(const char* filename);
|
||||
|
||||
int Video_LoadTexture(char *imagedata, u32 width, u32 height);
|
||||
void Video_DeleteTexture(int texID);
|
||||
void Video_DrawTexture(int texID, float *coords);
|
||||
|
||||
void Video_SetRendering(bool bEnabled);
|
||||
|
||||
void Video_GatherPipeBursted();
|
||||
bool Video_IsHiWatermarkActive();
|
||||
bool Video_IsPossibleWaitingSetDrawDone();
|
||||
void Video_AbortFrame();
|
||||
|
||||
readFn16 Video_CPRead16();
|
||||
writeFn16 Video_CPWrite16();
|
||||
readFn16 Video_PERead16();
|
||||
writeFn16 Video_PEWrite16();
|
||||
writeFn32 Video_PEWrite32();
|
||||
|
||||
void UpdateFPSDisplay(const char*);
|
||||
unsigned int PeekMessages();
|
||||
|
||||
void PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
public:
|
||||
void CheckInvalidState();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
131
Source/Core/VideoBackends/Software/Src/VideoConfigDialog.cpp
Normal file
131
Source/Core/VideoBackends/Software/Src/VideoConfigDialog.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoConfigDiag.h"
|
||||
#include "VideoConfigDialog.h"
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "Core.h"
|
||||
|
||||
template <typename T>
|
||||
IntegerSetting<T>::IntegerSetting(wxWindow* parent, const wxString& label, T& setting, int minVal, int maxVal, long style) :
|
||||
wxSpinCtrl(parent, -1, label, wxDefaultPosition, wxDefaultSize, style),
|
||||
m_setting(setting)
|
||||
{
|
||||
SetRange(minVal, maxVal);
|
||||
SetValue(m_setting);
|
||||
Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &IntegerSetting::UpdateValue, this);
|
||||
}
|
||||
|
||||
|
||||
VideoConfigDialog::VideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& _ininame) :
|
||||
wxDialog(parent, -1,
|
||||
wxString(wxT("Dolphin ")).append(StrToWxStr(title)).append(wxT(" Graphics Configuration")),
|
||||
wxDefaultPosition, wxDefaultSize),
|
||||
vconfig(g_SWVideoConfig),
|
||||
ininame(_ininame)
|
||||
{
|
||||
vconfig.Load((File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini").c_str());
|
||||
|
||||
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);
|
||||
|
||||
// - rendering
|
||||
{
|
||||
wxStaticBoxSizer* const group_rendering = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Rendering"));
|
||||
szr_general->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);
|
||||
|
||||
// backend
|
||||
wxStaticText* const label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:"));
|
||||
wxChoice* const choice_backend = new wxChoice(page_general, wxID_ANY, wxDefaultPosition);
|
||||
|
||||
std::vector<VideoBackend*>::const_iterator
|
||||
it = g_available_video_backends.begin(),
|
||||
itend = g_available_video_backends.end();
|
||||
for (; it != itend; ++it)
|
||||
choice_backend->AppendString(StrToWxStr((*it)->GetDisplayName()));
|
||||
|
||||
// TODO: How to get the translated plugin name?
|
||||
choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName()));
|
||||
choice_backend->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &VideoConfigDialog::Event_Backend, this);
|
||||
|
||||
szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
|
||||
szr_rendering->Add(choice_backend, 1, 0, 0);
|
||||
|
||||
if (Core::GetState() != Core::CORE_UNINITIALIZED)
|
||||
{
|
||||
label_backend->Disable();
|
||||
choice_backend->Disable();
|
||||
}
|
||||
|
||||
// rasterizer
|
||||
szr_rendering->Add(new SettingCheckBox(page_general, wxT("Hardware rasterization"), wxT(""), vconfig.bHwRasterizer));
|
||||
}
|
||||
|
||||
// - info
|
||||
{
|
||||
wxStaticBoxSizer* const group_info = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Overlay Information"));
|
||||
szr_general->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_general, wxT("Various Statistics"), wxT(""), vconfig.bShowStats));
|
||||
}
|
||||
|
||||
// - utility
|
||||
{
|
||||
wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Utility"));
|
||||
szr_general->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_general, wxT("Dump Textures"), wxT(""), vconfig.bDumpTextures));
|
||||
szr_utility->Add(new SettingCheckBox(page_general, wxT("Dump Objects"), wxT(""), vconfig.bDumpObjects));
|
||||
szr_utility->Add(new SettingCheckBox(page_general, wxT("Dump Frames"), wxT(""), vconfig.bDumpFrames));
|
||||
|
||||
// - debug only
|
||||
wxStaticBoxSizer* const group_debug_only_utility = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Debug Only"));
|
||||
group_utility->Add(group_debug_only_utility, 0, wxEXPAND | wxBOTTOM, 5);
|
||||
wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, 5, 5);
|
||||
group_debug_only_utility->Add(szr_debug_only_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||
|
||||
szr_debug_only_utility->Add(new SettingCheckBox(page_general, wxT("Dump TEV Stages"), wxT(""), vconfig.bDumpTevStages));
|
||||
szr_debug_only_utility->Add(new SettingCheckBox(page_general, wxT("Dump Texture Fetches"), wxT(""), vconfig.bDumpTevTextureFetches));
|
||||
}
|
||||
|
||||
// - misc
|
||||
{
|
||||
wxStaticBoxSizer* const group_misc = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Drawn Object Range"));
|
||||
szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||
wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5);
|
||||
group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
|
||||
|
||||
szr_misc->Add(new U32Setting(page_general, wxT("Start"), vconfig.drawStart, 0, 100000));
|
||||
szr_misc->Add(new U32Setting(page_general, wxT("End"), vconfig.drawEnd, 0, 100000));
|
||||
}
|
||||
|
||||
page_general->SetSizerAndFit(szr_general);
|
||||
}
|
||||
|
||||
wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
|
||||
szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
|
||||
szr_main->Add(new wxButton(this, wxID_OK, wxT("Close"), wxDefaultPosition),
|
||||
0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
|
||||
|
||||
SetSizerAndFit(szr_main);
|
||||
Center();
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
VideoConfigDialog::~VideoConfigDialog()
|
||||
{
|
||||
g_SWVideoConfig.Save((File::GetUserPath(D_CONFIG_IDX) + ininame + ".ini").c_str());
|
||||
}
|
52
Source/Core/VideoBackends/Software/Src/VideoConfigDialog.h
Normal file
52
Source/Core/VideoBackends/Software/Src/VideoConfigDialog.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VIDEOSOFTWARE_CONFIG_DIAG_H_
|
||||
#define _VIDEOSOFTWARE_CONFIG_DIAG_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "SWVideoConfig.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "ConfigManager.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>
|
||||
|
||||
class VideoConfigDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
VideoConfigDialog(wxWindow* parent, const std::string &title, const std::string& ininame);
|
||||
~VideoConfigDialog();
|
||||
|
||||
void Event_Backend(wxCommandEvent &ev)
|
||||
{
|
||||
VideoBackend* new_backend = g_available_video_backends[ev.GetInt()];
|
||||
|
||||
if (g_video_backend != new_backend)
|
||||
{
|
||||
Close();
|
||||
|
||||
g_video_backend = new_backend;
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend = g_video_backend->GetName();
|
||||
|
||||
g_video_backend->ShowConfig(GetParent());
|
||||
}
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
protected:
|
||||
SWVideoConfig& vconfig;
|
||||
std::string ininame;
|
||||
};
|
||||
|
||||
#endif
|
88
Source/Core/VideoBackends/Software/Src/XFMemLoader.cpp
Normal file
88
Source/Core/VideoBackends/Software/Src/XFMemLoader.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
#include "XFMemLoader.h"
|
||||
#include "CPMemLoader.h"
|
||||
#include "Clipper.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
XFRegisters swxfregs;
|
||||
|
||||
void InitXFMemory()
|
||||
{
|
||||
memset(&swxfregs, 0, sizeof(swxfregs));
|
||||
}
|
||||
|
||||
void XFWritten(u32 transferSize, u32 baseAddress)
|
||||
{
|
||||
u32 topAddress = baseAddress + transferSize;
|
||||
|
||||
if (baseAddress <= 0x1026 && topAddress >= 0x1020)
|
||||
Clipper::SetViewOffset();
|
||||
|
||||
// fix lights so invalid values don't trash the lighting computations
|
||||
if (baseAddress <= 0x067f && topAddress >= 0x0604)
|
||||
{
|
||||
u32* x = swxfregs.lights;
|
||||
|
||||
// go through all lights
|
||||
for (int light = 0; light < 8; light++)
|
||||
{
|
||||
// skip to floating point values
|
||||
x += 4;
|
||||
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
u32 xVal = *x;
|
||||
|
||||
// if the exponent is 255 then the number is inf or nan
|
||||
if ((xVal & 0x7f800000) == 0x7f800000)
|
||||
*x = 0;
|
||||
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SWLoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
|
||||
{
|
||||
u32 size = transferSize;
|
||||
|
||||
// do not allow writes past registers
|
||||
if (baseAddress + transferSize > 0x1058)
|
||||
{
|
||||
INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize);
|
||||
|
||||
if (baseAddress >= 0x1058)
|
||||
size = 0;
|
||||
else
|
||||
size = 0x1058 - baseAddress;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
memcpy_gc( &((u32*)&swxfregs)[baseAddress], pData, size * 4);
|
||||
XFWritten(transferSize, baseAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void SWLoadIndexedXF(u32 val, int array)
|
||||
{
|
||||
int index = val >> 16;
|
||||
int address = val & 0xFFF; //check mask
|
||||
int size = ((val >> 12) & 0xF) + 1;
|
||||
//load stuff from array to address in xf mem
|
||||
|
||||
u32 *pData = (u32*)Memory::GetPointer(arraybases[array] + arraystrides[array]*index);
|
||||
|
||||
// byteswap data
|
||||
u32 buffer[16];
|
||||
for (int i = 0; i < size; ++i)
|
||||
buffer[i] = Common::swap32(*(pData + i));
|
||||
|
||||
SWLoadXFReg(size, address, buffer);
|
||||
}
|
245
Source/Core/VideoBackends/Software/Src/XFMemLoader.h
Normal file
245
Source/Core/VideoBackends/Software/Src/XFMemLoader.h
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _XFMEMLOADER_H_
|
||||
#define _XFMEMLOADER_H_
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
/////////////
|
||||
// Lighting
|
||||
/////////////
|
||||
|
||||
#define XF_TEXPROJ_ST 0
|
||||
#define XF_TEXPROJ_STQ 1
|
||||
|
||||
#define XF_TEXINPUT_AB11 0
|
||||
#define XF_TEXINPUT_ABC1 1
|
||||
|
||||
#define XF_TEXGEN_REGULAR 0
|
||||
#define XF_TEXGEN_EMBOSS_MAP 1 // used when bump mapping
|
||||
#define XF_TEXGEN_COLOR_STRGBC0 2
|
||||
#define XF_TEXGEN_COLOR_STRGBC1 3
|
||||
|
||||
#define XF_SRCGEOM_INROW 0 // input is abc
|
||||
#define XF_SRCNORMAL_INROW 1 // input is abc
|
||||
#define XF_SRCCOLORS_INROW 2
|
||||
#define XF_SRCBINORMAL_T_INROW 3 // input is abc
|
||||
#define XF_SRCBINORMAL_B_INROW 4 // input is abc
|
||||
#define XF_SRCTEX0_INROW 5
|
||||
#define XF_SRCTEX1_INROW 6
|
||||
#define XF_SRCTEX2_INROW 7
|
||||
#define XF_SRCTEX3_INROW 8
|
||||
#define XF_SRCTEX4_INROW 9
|
||||
#define XF_SRCTEX5_INROW 10
|
||||
#define XF_SRCTEX6_INROW 11
|
||||
#define XF_SRCTEX7_INROW 12
|
||||
|
||||
#define GX_SRC_REG 0
|
||||
#define GX_SRC_VTX 1
|
||||
|
||||
struct Light
|
||||
{
|
||||
u32 useless[3];
|
||||
u32 color; //rgba
|
||||
float a0; //attenuation
|
||||
float a1;
|
||||
float a2;
|
||||
float k0; //k stuff
|
||||
float k1;
|
||||
float k2;
|
||||
union
|
||||
{
|
||||
struct {
|
||||
float dpos[3];
|
||||
float ddir[3]; // specular lights only
|
||||
};
|
||||
struct {
|
||||
float sdir[3];
|
||||
float shalfangle[3]; // specular lights only
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define LIGHTDIF_NONE 0
|
||||
#define LIGHTDIF_SIGN 1
|
||||
#define LIGHTDIF_CLAMP 2
|
||||
|
||||
#define LIGHTATTN_SPEC 0 // specular attenuation
|
||||
#define LIGHTATTN_SPOT 1 // distance/spotlight attenuation
|
||||
#define LIGHTATTN_NONE 2
|
||||
#define LIGHTATTN_DIR 3
|
||||
|
||||
#define GX_PERSPECTIVE 0
|
||||
#define GX_ORTHOGRAPHIC 1
|
||||
|
||||
union LitChannel
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 matsource : 1;
|
||||
u32 enablelighting : 1;
|
||||
u32 lightMask0_3 : 4;
|
||||
u32 ambsource : 1;
|
||||
u32 diffusefunc : 2; // LIGHTDIF_X
|
||||
u32 attnfunc : 2; // LIGHTATTN_X
|
||||
u32 lightMask4_7 : 4;
|
||||
u32 unused : 17;
|
||||
};
|
||||
u32 hex;
|
||||
unsigned int GetFullLightMask() const
|
||||
{
|
||||
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
union INVTXSPEC
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 numcolors : 2;
|
||||
u32 numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals
|
||||
u32 numtextures : 4;
|
||||
u32 unused : 24;
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
union TXFMatrixIndexA
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 PosNormalMtxIdx : 6;
|
||||
u32 Tex0MtxIdx : 6;
|
||||
u32 Tex1MtxIdx : 6;
|
||||
u32 Tex2MtxIdx : 6;
|
||||
u32 Tex3MtxIdx : 6;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 Hex : 30;
|
||||
u32 unused : 2;
|
||||
};
|
||||
};
|
||||
|
||||
union TXFMatrixIndexB
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 Tex4MtxIdx : 6;
|
||||
u32 Tex5MtxIdx : 6;
|
||||
u32 Tex6MtxIdx : 6;
|
||||
u32 Tex7MtxIdx : 6;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 Hex : 24;
|
||||
u32 unused : 8;
|
||||
};
|
||||
};
|
||||
|
||||
struct Viewport
|
||||
{
|
||||
float wd;
|
||||
float ht;
|
||||
float zRange;
|
||||
float xOrig;
|
||||
float yOrig;
|
||||
float farZ;
|
||||
};
|
||||
|
||||
struct Projection
|
||||
{
|
||||
float rawProjection[6];
|
||||
u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed
|
||||
};
|
||||
|
||||
union TexMtxInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 unknown : 1;
|
||||
u32 projection : 1; // XF_TEXPROJ_X
|
||||
u32 inputform : 2; // XF_TEXINPUT_X
|
||||
u32 texgentype : 3; // XF_TEXGEN_X
|
||||
u32 sourcerow : 5; // XF_SRCGEOM_X
|
||||
u32 embosssourceshift : 3; // what generated texcoord to use
|
||||
u32 embosslightshift : 3; // light index that is used
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
union PostMtxInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 index : 6; // base row of dual transform matrix
|
||||
u32 unused : 2;
|
||||
u32 normalize : 1; // normalize before send operation
|
||||
};
|
||||
u32 hex;
|
||||
};
|
||||
|
||||
struct XFRegisters
|
||||
{
|
||||
u32 posMatrices[256]; // 0x0000 - 0x00ff
|
||||
u32 unk0[768]; // 0x0100 - 0x03ff
|
||||
u32 normalMatrices[96]; // 0x0400 - 0x045f
|
||||
u32 unk1[160]; // 0x0460 - 0x04ff
|
||||
u32 postMatrices[256]; // 0x0500 - 0x05ff
|
||||
u32 lights[128]; // 0x0600 - 0x067f
|
||||
u32 unk2[2432]; // 0x0680 - 0x0fff
|
||||
u32 error; // 0x1000
|
||||
u32 diag; // 0x1001
|
||||
u32 state0; // 0x1002
|
||||
u32 state1; // 0x1003
|
||||
u32 xfClock; // 0x1004
|
||||
u32 clipDisable; // 0x1005
|
||||
u32 perf0; // 0x1006
|
||||
u32 perf1; // 0x1007
|
||||
INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input
|
||||
u32 nNumChans; // 0x1009
|
||||
u32 ambColor[2]; // 0x100a, 0x100b
|
||||
u32 matColor[2]; // 0x100c, 0x100d
|
||||
LitChannel color[2]; // 0x100e, 0x100f
|
||||
LitChannel alpha[2]; // 0x1010, 0x1011
|
||||
u32 dualTexTrans; // 0x1012
|
||||
u32 unk3; // 0x1013
|
||||
u32 unk4; // 0x1014
|
||||
u32 unk5; // 0x1015
|
||||
u32 unk6; // 0x1016
|
||||
u32 unk7; // 0x1017
|
||||
TXFMatrixIndexA MatrixIndexA; // 0x1018
|
||||
TXFMatrixIndexB MatrixIndexB; // 0x1019
|
||||
Viewport viewport; // 0x101a - 0x101f
|
||||
Projection projection; // 0x1020 - 0x1026
|
||||
u32 unk8[24]; // 0x1027 - 0x103e
|
||||
u32 numTexGens; // 0x103f
|
||||
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047
|
||||
u32 unk9[8]; // 0x1048 - 0x104f
|
||||
PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057
|
||||
};
|
||||
|
||||
#define XFMEM_POSMATRICES 0x000
|
||||
#define XFMEM_POSMATRICES_END 0x100
|
||||
#define XFMEM_NORMALMATRICES 0x400
|
||||
#define XFMEM_NORMALMATRICES_END 0x460
|
||||
#define XFMEM_POSTMATRICES 0x500
|
||||
#define XFMEM_POSTMATRICES_END 0x600
|
||||
#define XFMEM_LIGHTS 0x600
|
||||
#define XFMEM_LIGHTS_END 0x680
|
||||
|
||||
|
||||
extern XFRegisters swxfregs;
|
||||
|
||||
void InitXFMemory();
|
||||
|
||||
void XFWritten(u32 transferSize, u32 baseAddress);
|
||||
|
||||
void SWLoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData);
|
||||
|
||||
void SWLoadIndexedXF(u32 val, int array);
|
||||
|
||||
#endif
|
5
Source/Core/VideoBackends/Software/Src/stdafx.cpp
Normal file
5
Source/Core/VideoBackends/Software/Src/stdafx.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "stdafx.h"
|
13
Source/Core/VideoBackends/Software/Src/stdafx.h
Normal file
13
Source/Core/VideoBackends/Software/Src/stdafx.h
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
#define _WIN32_WINNT 0x501
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0500 // Default value is 0x0400
|
||||
#endif
|
||||
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
|
Reference in New Issue
Block a user