mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-09-12 21:37:59 -05:00
Put Plugins/ in Core/, rename to VideoBackends
This commit is contained in:
5
Source/Core/VideoBackends/CMakeLists.txt
Normal file
5
Source/Core/VideoBackends/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
if(NOT USE_GLES OR USE_GLES3)
|
||||
add_subdirectory(OGL)
|
||||
endif()
|
||||
add_subdirectory(Software)
|
||||
# TODO: Add other backends here!
|
||||
243
Source/Core/VideoBackends/D3D/D3D.vcxproj
Normal file
243
Source/Core/VideoBackends/D3D/D3D.vcxproj
Normal file
@@ -0,0 +1,243 @@
|
||||
<?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>{9A4C733C-BADE-4AC6-B58A-6E274395E90E}</ProjectGuid>
|
||||
<RootNamespace>VideoD3D</RootNamespace>
|
||||
<ProjectName>VideoD3D</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)'=='DebugFast|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<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)'=='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)'=='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|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)'=='DebugFast|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\VideoCommon\VideoCommon.vcxproj">
|
||||
<Project>{3e5c4e02-1ba9-4776-bdbe-e3f91ffa34cf}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\D3DBase.cpp" />
|
||||
<ClCompile Include="Src\D3DBlob.cpp" />
|
||||
<ClCompile Include="Src\D3DShader.cpp" />
|
||||
<ClCompile Include="Src\D3DTexture.cpp" />
|
||||
<ClCompile Include="Src\D3DUtil.cpp" />
|
||||
<ClCompile Include="Src\FramebufferManager.cpp" />
|
||||
<ClCompile Include="Src\GfxState.cpp" />
|
||||
<ClCompile Include="Src\LineGeometryShader.cpp" />
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="Src\PerfQuery.cpp" />
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp" />
|
||||
<ClCompile Include="Src\PointGeometryShader.cpp" />
|
||||
<ClCompile Include="Src\PSTextureEncoder.cpp" />
|
||||
<ClCompile Include="Src\Render.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Television.cpp" />
|
||||
<ClCompile Include="Src\TextureCache.cpp" />
|
||||
<ClCompile Include="Src\VertexManager.cpp" />
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp" />
|
||||
<ClCompile Include="Src\XFBEncoder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\D3DBase.h" />
|
||||
<ClInclude Include="Src\D3DBlob.h" />
|
||||
<ClInclude Include="Src\D3DShader.h" />
|
||||
<ClInclude Include="Src\D3DTexture.h" />
|
||||
<ClInclude Include="Src\D3DUtil.h" />
|
||||
<ClInclude Include="Src\FramebufferManager.h" />
|
||||
<ClInclude Include="Src\GfxState.h" />
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\LineGeometryShader.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\PerfQuery.h" />
|
||||
<ClInclude Include="Src\PixelShaderCache.h" />
|
||||
<ClInclude Include="Src\PointGeometryShader.h" />
|
||||
<ClInclude Include="Src\PSTextureEncoder.h" />
|
||||
<ClInclude Include="Src\Render.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\Television.h" />
|
||||
<ClInclude Include="Src\TextureCache.h" />
|
||||
<ClInclude Include="Src\TextureEncoder.h" />
|
||||
<ClInclude Include="Src\VertexManager.h" />
|
||||
<ClInclude Include="Src\VertexShaderCache.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\XFBEncoder.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
135
Source/Core/VideoBackends/D3D/D3D.vcxproj.filters
Normal file
135
Source/Core/VideoBackends/D3D/D3D.vcxproj.filters
Normal file
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp" />
|
||||
<ClCompile Include="Src\D3DBase.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\D3DBlob.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\D3DShader.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\D3DTexture.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\D3DUtil.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\GfxState.cpp">
|
||||
<Filter>D3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\FramebufferManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\VertexManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PSTextureEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\XFBEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Television.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\LineGeometryShader.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PointGeometryShader.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\D3DUtil.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\D3DBase.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\D3DBlob.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\D3DShader.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\D3DTexture.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\GfxState.h">
|
||||
<Filter>D3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Render.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PixelShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\VertexShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\VertexManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PSTextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\TextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\XFBEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Television.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\LineGeometryShader.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PointGeometryShader.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D">
|
||||
<UniqueIdentifier>{8dda993d-a0ed-4c2e-9651-c13c743e3e27}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Render">
|
||||
<UniqueIdentifier>{41d3f9d1-16f3-4a48-a486-292b1593dc92}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
534
Source/Core/VideoBackends/D3D/Src/D3DBase.cpp
Normal file
534
Source/Core/VideoBackends/D3D/Src/D3DBase.cpp
Normal file
@@ -0,0 +1,534 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "StringUtil.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DTexture.h"
|
||||
#include "GfxState.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
HINSTANCE hD3DCompilerDll = NULL;
|
||||
D3DREFLECT PD3DReflect = NULL;
|
||||
int d3dcompiler_dll_ref = 0;
|
||||
|
||||
HINSTANCE hD3DXDll = NULL;
|
||||
D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL;
|
||||
D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL;
|
||||
D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL;
|
||||
D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL;
|
||||
int d3dx_dll_ref = 0;
|
||||
|
||||
CREATEDXGIFACTORY PCreateDXGIFactory = NULL;
|
||||
HINSTANCE hDXGIDll = NULL;
|
||||
int dxgi_dll_ref = 0;
|
||||
|
||||
typedef HRESULT (WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, CONST DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
|
||||
D3D11CREATEDEVICE PD3D11CreateDevice = NULL;
|
||||
D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = NULL;
|
||||
HINSTANCE hD3DDll = NULL;
|
||||
int d3d_dll_ref = 0;
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
ID3D11Device* device = NULL;
|
||||
ID3D11DeviceContext* context = NULL;
|
||||
IDXGISwapChain* swapchain = NULL;
|
||||
D3D_FEATURE_LEVEL featlevel;
|
||||
D3DTexture2D* backbuf = NULL;
|
||||
HWND hWnd;
|
||||
|
||||
std::vector<DXGI_SAMPLE_DESC> aa_modes; // supported AA modes of the current adapter
|
||||
|
||||
bool bgra_textures_supported;
|
||||
|
||||
#define NUM_SUPPORTED_FEATURE_LEVELS 3
|
||||
const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = {
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0
|
||||
};
|
||||
|
||||
unsigned int xres, yres;
|
||||
|
||||
bool bFrameInProgress = false;
|
||||
|
||||
HRESULT LoadDXGI()
|
||||
{
|
||||
if (dxgi_dll_ref++ > 0) return S_OK;
|
||||
|
||||
if (hDXGIDll) return S_OK;
|
||||
hDXGIDll = LoadLibraryA("dxgi.dll");
|
||||
if (!hDXGIDll)
|
||||
{
|
||||
MessageBoxA(NULL, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR);
|
||||
--dxgi_dll_ref;
|
||||
return E_FAIL;
|
||||
}
|
||||
PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory");
|
||||
if (PCreateDXGIFactory == NULL) MessageBoxA(NULL, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT LoadD3D()
|
||||
{
|
||||
if (d3d_dll_ref++ > 0) return S_OK;
|
||||
|
||||
if (hD3DDll) return S_OK;
|
||||
hD3DDll = LoadLibraryA("d3d11.dll");
|
||||
if (!hD3DDll)
|
||||
{
|
||||
MessageBoxA(NULL, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR);
|
||||
--d3d_dll_ref;
|
||||
return E_FAIL;
|
||||
}
|
||||
PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice");
|
||||
if (PD3D11CreateDevice == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
PD3D11CreateDeviceAndSwapChain = (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain");
|
||||
if (PD3D11CreateDeviceAndSwapChain == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT LoadD3DX()
|
||||
{
|
||||
if (d3dx_dll_ref++ > 0) return S_OK;
|
||||
if (hD3DXDll) return S_OK;
|
||||
|
||||
// try to load D3DX11 first to check whether we have proper runtime support
|
||||
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
|
||||
hD3DXDll = LoadLibraryA(D3DX11_DLL_A);
|
||||
if (!hD3DXDll)
|
||||
{
|
||||
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
|
||||
hD3DXDll = LoadLibraryA("d3dx11_42.dll");
|
||||
if (!hD3DXDll)
|
||||
{
|
||||
MessageBoxA(NULL, "Failed to load d3dx11_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
|
||||
return E_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
NOTICE_LOG(VIDEO, "Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first.");
|
||||
}
|
||||
}
|
||||
|
||||
PD3DX11CompileFromMemory = (D3DX11COMPILEFROMMEMORYTYPE)GetProcAddress(hD3DXDll, "D3DX11CompileFromMemory");
|
||||
if (PD3DX11CompileFromMemory == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11CompileFromMemory!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
PD3DX11FilterTexture = (D3DX11FILTERTEXTURETYPE)GetProcAddress(hD3DXDll, "D3DX11FilterTexture");
|
||||
if (PD3DX11FilterTexture == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11FilterTexture!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
PD3DX11SaveTextureToFileA = (D3DX11SAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileA");
|
||||
if (PD3DX11SaveTextureToFileA == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
PD3DX11SaveTextureToFileW = (D3DX11SAVETEXTURETOFILEWTYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileW");
|
||||
if (PD3DX11SaveTextureToFileW == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileW!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT LoadD3DCompiler()
|
||||
{
|
||||
if (d3dcompiler_dll_ref++ > 0) return S_OK;
|
||||
if (hD3DCompilerDll) return S_OK;
|
||||
|
||||
// try to load D3DCompiler first to check whether we have proper runtime support
|
||||
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
|
||||
hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A);
|
||||
if (!hD3DCompilerDll)
|
||||
{
|
||||
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
|
||||
hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll");
|
||||
if (!hD3DCompilerDll)
|
||||
{
|
||||
MessageBoxA(NULL, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
|
||||
return E_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first.");
|
||||
}
|
||||
}
|
||||
|
||||
PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect");
|
||||
if (PD3DReflect == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DReflect!", "Critical error", MB_OK | MB_ICONERROR);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void UnloadDXGI()
|
||||
{
|
||||
if (!dxgi_dll_ref) return;
|
||||
if (--dxgi_dll_ref != 0) return;
|
||||
|
||||
if(hDXGIDll) FreeLibrary(hDXGIDll);
|
||||
hDXGIDll = NULL;
|
||||
PCreateDXGIFactory = NULL;
|
||||
}
|
||||
|
||||
void UnloadD3DX()
|
||||
{
|
||||
if (!d3dx_dll_ref) return;
|
||||
if (--d3dx_dll_ref != 0) return;
|
||||
|
||||
if(hD3DXDll) FreeLibrary(hD3DXDll);
|
||||
hD3DXDll = NULL;
|
||||
PD3DX11FilterTexture = NULL;
|
||||
PD3DX11SaveTextureToFileA = NULL;
|
||||
PD3DX11SaveTextureToFileW = NULL;
|
||||
}
|
||||
|
||||
void UnloadD3D()
|
||||
{
|
||||
if (!d3d_dll_ref) return;
|
||||
if (--d3d_dll_ref != 0) return;
|
||||
|
||||
if(hD3DDll) FreeLibrary(hD3DDll);
|
||||
hD3DDll = NULL;
|
||||
PD3D11CreateDevice = NULL;
|
||||
PD3D11CreateDeviceAndSwapChain = NULL;
|
||||
}
|
||||
|
||||
void UnloadD3DCompiler()
|
||||
{
|
||||
if (!d3dcompiler_dll_ref) return;
|
||||
if (--d3dcompiler_dll_ref != 0) return;
|
||||
|
||||
if (hD3DCompilerDll) FreeLibrary(hD3DCompilerDll);
|
||||
hD3DCompilerDll = NULL;
|
||||
PD3DReflect = NULL;
|
||||
}
|
||||
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
|
||||
{
|
||||
std::vector<DXGI_SAMPLE_DESC> aa_modes;
|
||||
|
||||
// NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND shader resources.
|
||||
// Thus, we can't have MSAA with 10.0 level hardware.
|
||||
ID3D11Device* device;
|
||||
ID3D11DeviceContext* context;
|
||||
D3D_FEATURE_LEVEL feat_level;
|
||||
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &device, &feat_level, &context);
|
||||
if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0)
|
||||
{
|
||||
DXGI_SAMPLE_DESC desc;
|
||||
desc.Count = 1;
|
||||
desc.Quality = 0;
|
||||
aa_modes.push_back(desc);
|
||||
SAFE_RELEASE(context);
|
||||
SAFE_RELEASE(device);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
|
||||
{
|
||||
UINT quality_levels = 0;
|
||||
device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels);
|
||||
if (quality_levels > 0) {
|
||||
DXGI_SAMPLE_DESC desc;
|
||||
desc.Count = samples;
|
||||
for (desc.Quality = 0; desc.Quality < quality_levels; ++desc.Quality)
|
||||
aa_modes.push_back(desc);
|
||||
}
|
||||
}
|
||||
context->Release();
|
||||
device->Release();
|
||||
}
|
||||
return aa_modes;
|
||||
}
|
||||
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
|
||||
{
|
||||
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
|
||||
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, NULL, &feat_level, NULL);
|
||||
return feat_level;
|
||||
}
|
||||
|
||||
DXGI_SAMPLE_DESC GetAAMode(int index)
|
||||
{
|
||||
return aa_modes[index];
|
||||
}
|
||||
|
||||
HRESULT Create(HWND wnd)
|
||||
{
|
||||
hWnd = wnd;
|
||||
HRESULT hr;
|
||||
|
||||
RECT client;
|
||||
GetClientRect(hWnd, &client);
|
||||
xres = client.right - client.left;
|
||||
yres = client.bottom - client.top;
|
||||
|
||||
hr = LoadDXGI();
|
||||
if (SUCCEEDED(hr)) hr = LoadD3D();
|
||||
if (SUCCEEDED(hr)) hr = LoadD3DX();
|
||||
if (SUCCEEDED(hr)) hr = LoadD3DCompiler();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
UnloadDXGI();
|
||||
UnloadD3D();
|
||||
UnloadD3DX();
|
||||
UnloadD3DCompiler();
|
||||
return hr;
|
||||
}
|
||||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* adapter;
|
||||
IDXGIOutput* output;
|
||||
hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
|
||||
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// try using the first one
|
||||
hr = factory->EnumAdapters(0, &adapter);
|
||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
// TODO: Make this configurable
|
||||
hr = adapter->EnumOutputs(0, &output);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// try using the first one
|
||||
hr = adapter->EnumOutputs(0, &output);
|
||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate outputs"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
// get supported AA modes
|
||||
aa_modes = EnumAAModes(adapter);
|
||||
if (g_Config.iMultisampleMode >= (int)aa_modes.size())
|
||||
{
|
||||
g_Config.iMultisampleMode = 0;
|
||||
UpdateActiveConfig();
|
||||
}
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
|
||||
memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
|
||||
swap_chain_desc.BufferCount = 1;
|
||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swap_chain_desc.OutputWindow = wnd;
|
||||
swap_chain_desc.SampleDesc.Count = 1;
|
||||
swap_chain_desc.SampleDesc.Quality = 0;
|
||||
swap_chain_desc.Windowed = TRUE;
|
||||
|
||||
DXGI_MODE_DESC mode_desc;
|
||||
memset(&mode_desc, 0, sizeof(mode_desc));
|
||||
mode_desc.Width = xres;
|
||||
mode_desc.Height = yres;
|
||||
mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, NULL);
|
||||
if (FAILED(hr)) MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
|
||||
// forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported!
|
||||
swap_chain_desc.BufferDesc.Width = xres;
|
||||
swap_chain_desc.BufferDesc.Height = yres;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
// Creating debug devices can sometimes fail if the user doesn't have the correct
|
||||
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
|
||||
{
|
||||
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
|
||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
|
||||
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
|
||||
&featlevel, &context);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
#endif
|
||||
{
|
||||
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED,
|
||||
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
|
||||
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
|
||||
&featlevel, &context);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
SAFE_RELEASE(device);
|
||||
SAFE_RELEASE(context);
|
||||
SAFE_RELEASE(swapchain);
|
||||
return E_FAIL;
|
||||
}
|
||||
SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
|
||||
SAFE_RELEASE(factory);
|
||||
SAFE_RELEASE(output);
|
||||
SAFE_RELEASE(adapter);
|
||||
|
||||
ID3D11Texture2D* buf;
|
||||
hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
SAFE_RELEASE(device);
|
||||
SAFE_RELEASE(context);
|
||||
SAFE_RELEASE(swapchain);
|
||||
return E_FAIL;
|
||||
}
|
||||
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
CHECK(backbuf!=NULL, "Create back buffer texture");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
|
||||
|
||||
context->OMSetRenderTargets(1, &backbuf->GetRTV(), NULL);
|
||||
|
||||
// BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware
|
||||
UINT format_support;
|
||||
device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support);
|
||||
bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
|
||||
|
||||
stateman = new StateManager;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
// release all bound resources
|
||||
context->ClearState();
|
||||
SAFE_RELEASE(backbuf);
|
||||
SAFE_RELEASE(swapchain);
|
||||
SAFE_DELETE(stateman);
|
||||
context->Flush(); // immediately destroy device objects
|
||||
|
||||
SAFE_RELEASE(context);
|
||||
ULONG references = device->Release();
|
||||
if (references)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
|
||||
}
|
||||
else
|
||||
{
|
||||
NOTICE_LOG(VIDEO, "Successfully released all device references!");
|
||||
}
|
||||
device = NULL;
|
||||
|
||||
// unload DLLs
|
||||
UnloadD3DX();
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
}
|
||||
|
||||
const char* VertexShaderVersionString()
|
||||
{
|
||||
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0";
|
||||
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "vs_4_1";
|
||||
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0";
|
||||
}
|
||||
|
||||
const char* GeometryShaderVersionString()
|
||||
{
|
||||
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "gs_5_0";
|
||||
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "gs_4_1";
|
||||
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "gs_4_0";
|
||||
}
|
||||
|
||||
const char* PixelShaderVersionString()
|
||||
{
|
||||
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0";
|
||||
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "ps_4_1";
|
||||
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "ps_4_0";
|
||||
}
|
||||
|
||||
D3DTexture2D* &GetBackBuffer() { return backbuf; }
|
||||
unsigned int GetBackBufferWidth() { return xres; }
|
||||
unsigned int GetBackBufferHeight() { return yres; }
|
||||
|
||||
bool BGRATexturesSupported() { return bgra_textures_supported; }
|
||||
|
||||
// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11
|
||||
unsigned int GetMaxTextureSize()
|
||||
{
|
||||
switch (featlevel)
|
||||
{
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
|
||||
case D3D_FEATURE_LEVEL_9_3:
|
||||
return 4096;
|
||||
|
||||
case D3D_FEATURE_LEVEL_9_2:
|
||||
case D3D_FEATURE_LEVEL_9_1:
|
||||
return 2048;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
// release all back buffer references
|
||||
SAFE_RELEASE(backbuf);
|
||||
|
||||
// resize swapchain buffers
|
||||
RECT client;
|
||||
GetClientRect(hWnd, &client);
|
||||
xres = client.right - client.left;
|
||||
yres = client.bottom - client.top;
|
||||
D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
|
||||
|
||||
// recreate back buffer texture
|
||||
ID3D11Texture2D* buf;
|
||||
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
|
||||
SAFE_RELEASE(device);
|
||||
SAFE_RELEASE(context);
|
||||
SAFE_RELEASE(swapchain);
|
||||
return;
|
||||
}
|
||||
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
CHECK(backbuf!=NULL, "Create back buffer texture");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
|
||||
}
|
||||
|
||||
bool BeginFrame()
|
||||
{
|
||||
if (bFrameInProgress)
|
||||
{
|
||||
PanicAlert("BeginFrame called although a frame is already in progress");
|
||||
return false;
|
||||
}
|
||||
bFrameInProgress = true;
|
||||
return (device != NULL);
|
||||
}
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
if (!bFrameInProgress)
|
||||
{
|
||||
PanicAlert("EndFrame called although no frame is in progress");
|
||||
return;
|
||||
}
|
||||
bFrameInProgress = false;
|
||||
}
|
||||
|
||||
void Present()
|
||||
{
|
||||
// TODO: Is 1 the correct value for vsyncing?
|
||||
swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0);
|
||||
}
|
||||
|
||||
} // namespace D3D
|
||||
|
||||
} // namespace DX11
|
||||
106
Source/Core/VideoBackends/D3D/Src/D3DBase.h
Normal file
106
Source/Core/VideoBackends/D3D/Src/D3DBase.h
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <D3DX11.h>
|
||||
#include <D3Dcompiler.h>
|
||||
#include "Common.h"
|
||||
#include <vector>
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; }
|
||||
#define SAFE_DELETE(x) { delete (x); (x) = NULL; }
|
||||
#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = NULL; }
|
||||
#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
|
||||
|
||||
class D3DTexture2D;
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
HRESULT LoadDXGI();
|
||||
HRESULT LoadD3D();
|
||||
HRESULT LoadD3DX();
|
||||
HRESULT LoadD3DCompiler();
|
||||
void UnloadDXGI();
|
||||
void UnloadD3D();
|
||||
void UnloadD3DX();
|
||||
void UnloadD3DCompiler();
|
||||
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter);
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
|
||||
DXGI_SAMPLE_DESC GetAAMode(int index);
|
||||
|
||||
HRESULT Create(HWND wnd);
|
||||
void Close();
|
||||
|
||||
extern ID3D11Device* device;
|
||||
extern ID3D11DeviceContext* context;
|
||||
extern IDXGISwapChain* swapchain;
|
||||
extern bool bFrameInProgress;
|
||||
|
||||
void Reset();
|
||||
bool BeginFrame();
|
||||
void EndFrame();
|
||||
void Present();
|
||||
|
||||
unsigned int GetBackBufferWidth();
|
||||
unsigned int GetBackBufferHeight();
|
||||
D3DTexture2D* &GetBackBuffer();
|
||||
const char* PixelShaderVersionString();
|
||||
const char* GeometryShaderVersionString();
|
||||
const char* VertexShaderVersionString();
|
||||
bool BGRATexturesSupported();
|
||||
|
||||
unsigned int GetMaxTextureSize();
|
||||
|
||||
// Ihis function will assign a name to the given resource.
|
||||
// The DirectX debug layer will make it easier to identify resources that way,
|
||||
// e.g. when listing up all resources who have unreleased references.
|
||||
template <typename T>
|
||||
void SetDebugObjectName(T resource, const char* name)
|
||||
{
|
||||
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
|
||||
"resource must be convertible to ID3D11DeviceChild*");
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(name), name);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// Used to not require the SDK and runtime versions to match:
|
||||
// Linking with d3dx11.lib makes the most recent d3dx11_xx.dll of the
|
||||
// compiler's SDK a requirement, but this backend works with DX11 runtimes
|
||||
// back to August 2009 even if the backend was built with June 2010.
|
||||
// Add any d3dx11 functions which you want to use here and load them in Create()
|
||||
typedef HRESULT (WINAPI* D3DX11COMPILEFROMMEMORYTYPE)(LPCSTR, SIZE_T, LPCSTR, const D3D10_SHADER_MACRO*, LPD3D10INCLUDE, LPCSTR, LPCSTR, UINT, UINT, ID3DX11ThreadPump*, ID3D10Blob**, ID3D10Blob**, HRESULT*);
|
||||
typedef HRESULT (WINAPI* D3DX11FILTERTEXTURETYPE)(ID3D11DeviceContext*, ID3D11Resource*, UINT, UINT);
|
||||
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEATYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCSTR);
|
||||
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEWTYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCWSTR);
|
||||
|
||||
extern D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory;
|
||||
extern D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture;
|
||||
extern D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA;
|
||||
extern D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW;
|
||||
|
||||
#ifdef UNICODE
|
||||
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileW
|
||||
#else
|
||||
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileA
|
||||
#endif
|
||||
|
||||
typedef HRESULT (WINAPI* CREATEDXGIFACTORY)(REFIID, void**);
|
||||
extern CREATEDXGIFACTORY PCreateDXGIFactory;
|
||||
typedef HRESULT (WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
|
||||
extern D3D11CREATEDEVICE PD3D11CreateDevice;
|
||||
|
||||
typedef HRESULT (WINAPI *D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**);
|
||||
extern D3DREFLECT PD3DReflect;
|
||||
|
||||
} // namespace DX11
|
||||
56
Source/Core/VideoBackends/D3D/Src/D3DBlob.cpp
Normal file
56
Source/Core/VideoBackends/D3D/Src/D3DBlob.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <d3d11.h>
|
||||
#include "D3DBlob.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(NULL)
|
||||
{
|
||||
data = new u8[blob_size];
|
||||
if (init_data) memcpy(data, init_data, size);
|
||||
}
|
||||
|
||||
D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1)
|
||||
{
|
||||
blob = d3dblob;
|
||||
data = (u8*)blob->GetBufferPointer();
|
||||
size = (unsigned int)blob->GetBufferSize();
|
||||
d3dblob->AddRef();
|
||||
}
|
||||
|
||||
D3DBlob::~D3DBlob()
|
||||
{
|
||||
if (blob) blob->Release();
|
||||
else delete[] data;
|
||||
}
|
||||
|
||||
void D3DBlob::AddRef()
|
||||
{
|
||||
++ref;
|
||||
}
|
||||
|
||||
unsigned int D3DBlob::Release()
|
||||
{
|
||||
if (--ref == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
unsigned int D3DBlob::Size()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
u8* D3DBlob::Data()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
40
Source/Core/VideoBackends/D3D/Src/D3DBlob.h
Normal file
40
Source/Core/VideoBackends/D3D/Src/D3DBlob.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CommonTypes.h"
|
||||
|
||||
struct ID3D10Blob;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// use this class instead ID3D10Blob or ID3D11Blob whenever possible
|
||||
class D3DBlob
|
||||
{
|
||||
public:
|
||||
// memory will be copied into an own buffer
|
||||
D3DBlob(unsigned int blob_size, const u8* init_data = NULL);
|
||||
|
||||
// d3dblob will be AddRef'd
|
||||
D3DBlob(ID3D10Blob* d3dblob);
|
||||
|
||||
void AddRef();
|
||||
unsigned int Release();
|
||||
|
||||
unsigned int Size();
|
||||
u8* Data();
|
||||
|
||||
private:
|
||||
~D3DBlob();
|
||||
|
||||
unsigned int ref;
|
||||
unsigned int size;
|
||||
|
||||
u8* data;
|
||||
ID3D10Blob* blob;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
236
Source/Core/VideoBackends/D3D/Src/D3DShader.cpp
Normal file
236
Source/Core/VideoBackends/D3D/Src/D3DShader.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
{
|
||||
ID3D11VertexShader* v_shader;
|
||||
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader);
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
|
||||
return v_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = NULL;
|
||||
ID3D10Blob* errorBuffer = NULL;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
|
||||
#endif
|
||||
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::VertexShaderVersionString(),
|
||||
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s\n",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
|
||||
szTemp,
|
||||
D3D::VertexShaderVersionString(),
|
||||
(char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = NULL;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
{
|
||||
ID3D11GeometryShader* g_shader;
|
||||
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, NULL, &g_shader);
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
|
||||
return g_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileGeometryShader(const char* code, unsigned int len, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = NULL;
|
||||
ID3D10Blob* errorBuffer = NULL;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
|
||||
#endif
|
||||
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, pDefines, NULL, "main", D3D::GeometryShaderVersionString(),
|
||||
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_gs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile geometry shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
|
||||
szTemp,
|
||||
D3D::GeometryShaderVersionString(),
|
||||
(char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = NULL;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len)
|
||||
{
|
||||
ID3D11PixelShader* p_shader;
|
||||
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, NULL, &p_shader);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
|
||||
p_shader = NULL;
|
||||
}
|
||||
return p_shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = NULL;
|
||||
ID3D10Blob* errorBuffer = NULL;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
|
||||
#endif
|
||||
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, pDefines, NULL, "main", D3D::PixelShaderVersionString(),
|
||||
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
|
||||
szTemp,
|
||||
D3D::PixelShaderVersionString(),
|
||||
(char*)errorBuffer->GetBufferPointer());
|
||||
|
||||
*blob = NULL;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
|
||||
unsigned int len)
|
||||
{
|
||||
D3DBlob* blob = NULL;
|
||||
if (CompileVertexShader(code, len, &blob))
|
||||
{
|
||||
ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return v_shader;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
|
||||
unsigned int len, const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
D3DBlob* blob = NULL;
|
||||
if (CompileGeometryShader(code, len, &blob, pDefines))
|
||||
{
|
||||
ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return g_shader;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
|
||||
unsigned int len)
|
||||
{
|
||||
D3DBlob* blob = NULL;
|
||||
CompilePixelShader(code, len, &blob);
|
||||
if (blob)
|
||||
{
|
||||
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return p_shader;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX11
|
||||
53
Source/Core/VideoBackends/D3D/Src/D3DShader.h
Normal file
53
Source/Core/VideoBackends/D3D/Src/D3DShader.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DBlob.h"
|
||||
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11VertexShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
|
||||
|
||||
// The returned bytecode buffers should be Release()d.
|
||||
bool CompileVertexShader(const char* code, unsigned int len,
|
||||
D3DBlob** blob);
|
||||
bool CompileGeometryShader(const char* code, unsigned int len,
|
||||
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
|
||||
bool CompilePixelShader(const char* code, unsigned int len,
|
||||
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
|
||||
|
||||
// Utility functions
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
|
||||
unsigned int len);
|
||||
ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
|
||||
unsigned int len, const D3D_SHADER_MACRO* pDefines = NULL);
|
||||
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
|
||||
unsigned int len);
|
||||
|
||||
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
|
||||
{ return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
|
||||
inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
|
||||
{ return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
|
||||
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
|
||||
{ return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
|
||||
|
||||
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
|
||||
{ return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); }
|
||||
inline ID3D11GeometryShader* CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = NULL)
|
||||
{ return CompileAndCreateGeometryShader((const char*)code->Data(), code->Size(), pDefines); }
|
||||
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
|
||||
{ return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
107
Source/Core/VideoBackends/D3D/Src/D3DTexture.cpp
Normal file
107
Source/Core/VideoBackends/D3D/Src/D3DTexture.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DTexture.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
||||
{
|
||||
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
if (4 * pitch == map.RowPitch)
|
||||
{
|
||||
memcpy(map.pData, buffer, map.RowPitch * height);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, 4 * pitch);
|
||||
}
|
||||
D3D::context->Unmap(pTexture, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1);
|
||||
D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels)
|
||||
{
|
||||
ID3D11Texture2D* pTexture = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_CPU_ACCESS_FLAG cpuflags;
|
||||
if (usage == D3D11_USAGE_STAGING) cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ);
|
||||
else if (usage == D3D11_USAGE_DYNAMIC) cpuflags = D3D11_CPU_ACCESS_WRITE;
|
||||
else cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
|
||||
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, 1, levels, bind, usage, cpuflags);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &pTexture);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
|
||||
SAFE_RELEASE(pTexture);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3DTexture2D::AddRef()
|
||||
{
|
||||
++ref;
|
||||
}
|
||||
|
||||
UINT D3DTexture2D::Release()
|
||||
{
|
||||
--ref;
|
||||
if (ref == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* &D3DTexture2D::GetTex() { return tex; }
|
||||
ID3D11ShaderResourceView* &D3DTexture2D::GetSRV() { return srv; }
|
||||
ID3D11RenderTargetView* &D3DTexture2D::GetRTV() { return rtv; }
|
||||
ID3D11DepthStencilView* &D3DTexture2D::GetDSV() { return dsv; }
|
||||
|
||||
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind,
|
||||
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled)
|
||||
: ref(1), tex(texptr), srv(NULL), rtv(NULL), dsv(NULL)
|
||||
{
|
||||
D3D11_SRV_DIMENSION srv_dim = multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
D3D11_DSV_DIMENSION dsv_dim = multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
D3D11_RTV_DIMENSION rtv_dim = multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format);
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format);
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format);
|
||||
if (bind & D3D11_BIND_SHADER_RESOURCE) D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (bind & D3D11_BIND_RENDER_TARGET) D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv);
|
||||
if (bind & D3D11_BIND_DEPTH_STENCIL) D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv);
|
||||
tex->AddRef();
|
||||
}
|
||||
|
||||
D3DTexture2D::~D3DTexture2D()
|
||||
{
|
||||
SAFE_RELEASE(srv);
|
||||
SAFE_RELEASE(rtv);
|
||||
SAFE_RELEASE(dsv);
|
||||
SAFE_RELEASE(tex);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
47
Source/Core/VideoBackends/D3D/Src/D3DTexture.h
Normal file
47
Source/Core/VideoBackends/D3D/Src/D3DTexture.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
|
||||
}
|
||||
|
||||
class D3DTexture2D
|
||||
{
|
||||
public:
|
||||
// there are two ways to create a D3DTexture2D object:
|
||||
// either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create
|
||||
// or let the texture automatically be created by D3DTexture2D::Create
|
||||
|
||||
D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false);
|
||||
static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1);
|
||||
|
||||
// reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore
|
||||
void AddRef();
|
||||
UINT Release();
|
||||
|
||||
ID3D11Texture2D* &GetTex();
|
||||
ID3D11ShaderResourceView* &GetSRV();
|
||||
ID3D11RenderTargetView* &GetRTV();
|
||||
ID3D11DepthStencilView* &GetDSV();
|
||||
|
||||
private:
|
||||
~D3DTexture2D();
|
||||
|
||||
ID3D11Texture2D* tex;
|
||||
ID3D11ShaderResourceView* srv;
|
||||
ID3D11RenderTargetView* rtv;
|
||||
ID3D11DepthStencilView* dsv;
|
||||
D3D11_BIND_FLAG bindflags;
|
||||
UINT ref;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
685
Source/Core/VideoBackends/D3D/Src/D3DUtil.cpp
Normal file
685
Source/Core/VideoBackends/D3D/Src/D3DUtil.cpp
Normal file
@@ -0,0 +1,685 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DUtil.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "D3DShader.h"
|
||||
#include "GfxState.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
// Ring buffer class, shared between the draw* functions
|
||||
class UtilVertexBuffer
|
||||
{
|
||||
public:
|
||||
UtilVertexBuffer(int size) : buf(NULL), offset(0), max_size(size)
|
||||
{
|
||||
D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
device->CreateBuffer(&desc, NULL, &buf);
|
||||
}
|
||||
~UtilVertexBuffer()
|
||||
{
|
||||
buf->Release();
|
||||
}
|
||||
|
||||
// returns vertex offset to the new data
|
||||
int AppendData(void* data, int size, int vertex_size)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
if(offset + size >= max_size)
|
||||
{
|
||||
// wrap buffer around and notify observers
|
||||
offset = 0;
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
|
||||
for(std::list<bool*>::iterator it = observers.begin(); it != observers.end(); ++it)
|
||||
**it = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
|
||||
}
|
||||
offset = ((offset+vertex_size-1)/vertex_size)*vertex_size; // align offset to vertex_size bytes
|
||||
memcpy((u8*)map.pData + offset, data, size);
|
||||
context->Unmap(buf, 0);
|
||||
|
||||
offset += size;
|
||||
return (offset - size) / vertex_size;
|
||||
}
|
||||
|
||||
void AddWrapObserver(bool* observer)
|
||||
{
|
||||
observers.push_back(observer);
|
||||
}
|
||||
|
||||
inline ID3D11Buffer* &GetBuffer() { return buf; }
|
||||
|
||||
private:
|
||||
ID3D11Buffer* buf;
|
||||
int offset;
|
||||
int max_size;
|
||||
|
||||
std::list<bool*> observers;
|
||||
};
|
||||
|
||||
CD3DFont font;
|
||||
UtilVertexBuffer* util_vbuf = NULL;
|
||||
|
||||
#define MAX_NUM_VERTICES 50*6
|
||||
struct FONT2DVERTEX {
|
||||
float x,y,z;
|
||||
float col[4];
|
||||
float tu, tv;
|
||||
};
|
||||
|
||||
inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv)
|
||||
{
|
||||
FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv;
|
||||
v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f;
|
||||
v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f;
|
||||
v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f;
|
||||
v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f;
|
||||
return v;
|
||||
}
|
||||
|
||||
CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512)
|
||||
{
|
||||
m_pTexture = NULL;
|
||||
m_pVB = NULL;
|
||||
m_InputLayout = NULL;
|
||||
m_pshader = NULL;
|
||||
m_vshader = NULL;
|
||||
}
|
||||
|
||||
const char fontpixshader[] = {
|
||||
"Texture2D tex2D;\n"
|
||||
"SamplerState linearSampler\n"
|
||||
"{\n"
|
||||
" Filter = MIN_MAG_MIP_LINEAR;\n"
|
||||
" AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n"
|
||||
" AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n"
|
||||
" BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n"
|
||||
"};\n"
|
||||
"struct PS_INPUT\n"
|
||||
"{\n"
|
||||
" float4 pos : SV_POSITION;\n"
|
||||
" float4 col : COLOR;\n"
|
||||
" float2 tex : TEXCOORD;\n"
|
||||
"};\n"
|
||||
"float4 main( PS_INPUT input ) : SV_Target\n"
|
||||
"{\n"
|
||||
" return tex2D.Sample( linearSampler, input.tex ) * input.col;\n"
|
||||
"};\n"
|
||||
};
|
||||
|
||||
const char fontvertshader[] = {
|
||||
"struct VS_INPUT\n"
|
||||
"{\n"
|
||||
" float4 pos : POSITION;\n"
|
||||
" float4 col : COLOR;\n"
|
||||
" float2 tex : TEXCOORD;\n"
|
||||
"};\n"
|
||||
"struct PS_INPUT\n"
|
||||
"{\n"
|
||||
" float4 pos : SV_POSITION;\n"
|
||||
" float4 col : COLOR;\n"
|
||||
" float2 tex : TEXCOORD;\n"
|
||||
"};\n"
|
||||
"PS_INPUT main( VS_INPUT input )\n"
|
||||
"{\n"
|
||||
" PS_INPUT output;\n"
|
||||
" output.pos = input.pos;\n"
|
||||
" output.col = input.col;\n"
|
||||
" output.tex = input.tex;\n"
|
||||
" return output;\n"
|
||||
"};\n"
|
||||
};
|
||||
|
||||
int CD3DFont::Init()
|
||||
{
|
||||
// Create vertex buffer for the letters
|
||||
HRESULT hr;
|
||||
|
||||
// Prepare to create a bitmap
|
||||
unsigned int* pBitmapBits;
|
||||
BITMAPINFO bmi;
|
||||
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
|
||||
bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
|
||||
// Create a DC and a bitmap for the font
|
||||
HDC hDC = CreateCompatibleDC(NULL);
|
||||
HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
|
||||
SetMapMode(hDC, MM_TEXT);
|
||||
|
||||
// create a GDI font
|
||||
HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE,
|
||||
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
|
||||
VARIABLE_PITCH, _T("Tahoma"));
|
||||
if (NULL == hFont) return E_FAIL;
|
||||
|
||||
HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
|
||||
HGDIOBJ hOldFont = SelectObject(hDC, hFont);
|
||||
|
||||
// Set text properties
|
||||
SetTextColor(hDC, 0xFFFFFF);
|
||||
SetBkColor (hDC, 0);
|
||||
SetTextAlign(hDC, TA_TOP);
|
||||
|
||||
TEXTMETRICW tm;
|
||||
GetTextMetricsW(hDC, &tm);
|
||||
m_LineHeight = tm.tmHeight;
|
||||
|
||||
// Loop through all printable characters and output them to the bitmap
|
||||
// Meanwhile, keep track of the corresponding tex coords for each character.
|
||||
int x = 0, y = 0;
|
||||
char str[2] = "\0";
|
||||
for (int c = 0; c < 127 - 32; c++)
|
||||
{
|
||||
str[0] = c + 32;
|
||||
SIZE size;
|
||||
GetTextExtentPoint32A(hDC, str, 1, &size);
|
||||
if ((int)(x+size.cx+1) > m_dwTexWidth)
|
||||
{
|
||||
x = 0;
|
||||
y += m_LineHeight;
|
||||
}
|
||||
|
||||
ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL);
|
||||
m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth;
|
||||
m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight;
|
||||
m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
|
||||
m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
|
||||
|
||||
x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i)
|
||||
}
|
||||
|
||||
// Create a new texture for the font
|
||||
// possible optimization: store the converted data in a buffer and fill the texture on creation.
|
||||
// That way, we can use a static texture
|
||||
ID3D11Texture2D* buftex;
|
||||
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight,
|
||||
1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC,
|
||||
D3D11_CPU_ACCESS_WRITE);
|
||||
hr = device->CreateTexture2D(&texdesc, NULL, &buftex);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create font texture");
|
||||
return hr;
|
||||
}
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object");
|
||||
|
||||
// Lock the surface and write the alpha values for the set pixels
|
||||
D3D11_MAPPED_SUBRESOURCE texmap;
|
||||
hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap);
|
||||
if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__);
|
||||
|
||||
for (y = 0; y < m_dwTexHeight; y++)
|
||||
{
|
||||
u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch);
|
||||
for (x = 0; x < m_dwTexWidth; x++)
|
||||
{
|
||||
const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff);
|
||||
*pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Done updating texture, so clean up used objects
|
||||
context->Unmap(buftex, 0);
|
||||
hr = D3D::device->CreateShaderResourceView(buftex, NULL, &m_pTexture);
|
||||
if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__);
|
||||
SAFE_RELEASE(buftex);
|
||||
|
||||
SelectObject(hDC, hOldbmBitmap);
|
||||
DeleteObject(hbmBitmap);
|
||||
|
||||
SelectObject(hDC, hOldFont);
|
||||
DeleteObject(hFont);
|
||||
|
||||
// setup device objects for drawing
|
||||
m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader, sizeof(fontpixshader));
|
||||
if (m_pshader == NULL) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object");
|
||||
|
||||
D3DBlob* vsbytecode;
|
||||
D3D::CompileVertexShader(fontvertshader, sizeof(fontvertshader), &vsbytecode);
|
||||
if (vsbytecode == NULL) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__);
|
||||
m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode);
|
||||
if (m_vshader == NULL) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object");
|
||||
|
||||
const D3D11_INPUT_ELEMENT_DESC desc[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout);
|
||||
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
||||
SAFE_RELEASE(vsbytecode);
|
||||
|
||||
D3D11_BLEND_DESC blenddesc;
|
||||
blenddesc.AlphaToCoverageEnable = FALSE;
|
||||
blenddesc.IndependentBlendEnable = FALSE;
|
||||
blenddesc.RenderTarget[0].BlendEnable = TRUE;
|
||||
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
|
||||
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate);
|
||||
CHECK(hr==S_OK, "Create font blend state");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object");
|
||||
|
||||
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false);
|
||||
hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate);
|
||||
CHECK(hr==S_OK, "Create font rasterizer state");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object");
|
||||
|
||||
D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
if (FAILED(hr = device->CreateBuffer(&vbdesc, NULL, &m_pVB)))
|
||||
{
|
||||
PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__);
|
||||
return hr;
|
||||
}
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int CD3DFont::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(m_pVB);
|
||||
SAFE_RELEASE(m_pTexture);
|
||||
SAFE_RELEASE(m_InputLayout);
|
||||
SAFE_RELEASE(m_pshader);
|
||||
SAFE_RELEASE(m_vshader);
|
||||
|
||||
SAFE_RELEASE(m_blendstate);
|
||||
SAFE_RELEASE(m_raststate);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const char* strText)
|
||||
{
|
||||
if (!m_pVB)
|
||||
return 0;
|
||||
|
||||
UINT stride = sizeof(FONT2DVERTEX);
|
||||
UINT bufoffset = 0;
|
||||
|
||||
float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f;
|
||||
float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f;
|
||||
float sizeratio = size / (float)m_LineHeight;
|
||||
|
||||
// translate starting positions
|
||||
float sx = x * scalex - 1.f;
|
||||
float sy = 1.f - y * scaley;
|
||||
char c;
|
||||
|
||||
// Fill vertex buffer
|
||||
FONT2DVERTEX* pVertices;
|
||||
int dwNumTriangles = 0L;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE vbmap;
|
||||
HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
|
||||
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
|
||||
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
|
||||
|
||||
// set general pipeline state
|
||||
D3D::stateman->PushBlendState(m_blendstate);
|
||||
D3D::stateman->PushRasterizerState(m_raststate);
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D::context->PSSetShader(m_pshader, NULL, 0);
|
||||
D3D::context->VSSetShader(m_vshader, NULL, 0);
|
||||
|
||||
D3D::context->IASetInputLayout(m_InputLayout);
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
D3D::context->PSSetShaderResources(0, 1, &m_pTexture);
|
||||
|
||||
float fStartX = sx;
|
||||
while (c = *strText++)
|
||||
{
|
||||
if (c == ('\n'))
|
||||
{
|
||||
sx = fStartX;
|
||||
sy -= scaley * size;
|
||||
}
|
||||
if (c < (' '))
|
||||
continue;
|
||||
|
||||
c -= 32;
|
||||
float tx1 = m_fTexCoords[c][0];
|
||||
float ty1 = m_fTexCoords[c][1];
|
||||
float tx2 = m_fTexCoords[c][2];
|
||||
float ty2 = m_fTexCoords[c][3];
|
||||
|
||||
float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio;
|
||||
float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio;
|
||||
|
||||
FONT2DVERTEX v[6];
|
||||
v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2);
|
||||
v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1);
|
||||
v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2);
|
||||
v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1);
|
||||
v[4] = v[2];
|
||||
v[5] = v[1];
|
||||
|
||||
memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX));
|
||||
|
||||
pVertices+=6;
|
||||
dwNumTriangles += 2;
|
||||
|
||||
if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
|
||||
{
|
||||
context->Unmap(m_pVB, 0);
|
||||
|
||||
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
|
||||
D3D::context->Draw(3 * dwNumTriangles, 0);
|
||||
|
||||
dwNumTriangles = 0;
|
||||
D3D11_MAPPED_SUBRESOURCE vbmap;
|
||||
hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
|
||||
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
|
||||
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
|
||||
}
|
||||
sx += w + spacing * scalex * size;
|
||||
}
|
||||
|
||||
// Unlock and render the vertex buffer
|
||||
context->Unmap(m_pVB, 0);
|
||||
if (dwNumTriangles > 0)
|
||||
{
|
||||
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
|
||||
D3D::context->Draw(3 * dwNumTriangles, 0);
|
||||
}
|
||||
D3D::stateman->PopBlendState();
|
||||
D3D::stateman->PopRasterizerState();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ID3D11SamplerState* linear_copy_sampler = NULL;
|
||||
ID3D11SamplerState* point_copy_sampler = NULL;
|
||||
|
||||
typedef struct { float x,y,z,u,v,w; } STQVertex;
|
||||
typedef struct { float x,y,z,u,v,w; } STSQVertex;
|
||||
typedef struct { float x,y,z; u32 col; } ClearVertex;
|
||||
typedef struct { float x,y,z; u32 col; } ColVertex;
|
||||
|
||||
struct
|
||||
{
|
||||
float u1, v1, u2, v2, G;
|
||||
} tex_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
MathUtil::Rectangle<float> rdest;
|
||||
float u1, v1, u2, v2, G;
|
||||
} tex_sub_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
u32 col;
|
||||
} draw_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 col;
|
||||
float z;
|
||||
} clear_quad_data;
|
||||
|
||||
// ring buffer offsets
|
||||
int stq_offset, stsq_offset, cq_offset, clearq_offset;
|
||||
|
||||
// observer variables for ring buffer wraps
|
||||
bool stq_observer, stsq_observer, cq_observer, clearq_observer;
|
||||
|
||||
void InitUtils()
|
||||
{
|
||||
util_vbuf = new UtilVertexBuffer(0x4000);
|
||||
|
||||
float border[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
|
||||
HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler);
|
||||
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
||||
else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state");
|
||||
|
||||
samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
|
||||
hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler);
|
||||
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
|
||||
else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state");
|
||||
|
||||
// cached data used to avoid unnecessarily reloading the vertex buffers
|
||||
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
|
||||
memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data));
|
||||
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
|
||||
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
|
||||
|
||||
// make sure to properly load the vertex data whenever the corresponding functions get called the first time
|
||||
stq_observer = stsq_observer = cq_observer = clearq_observer = true;
|
||||
util_vbuf->AddWrapObserver(&stq_observer);
|
||||
util_vbuf->AddWrapObserver(&stsq_observer);
|
||||
util_vbuf->AddWrapObserver(&cq_observer);
|
||||
util_vbuf->AddWrapObserver(&clearq_observer);
|
||||
|
||||
font.Init();
|
||||
}
|
||||
|
||||
void ShutdownUtils()
|
||||
{
|
||||
font.Shutdown();
|
||||
SAFE_RELEASE(point_copy_sampler);
|
||||
SAFE_RELEASE(linear_copy_sampler);
|
||||
SAFE_DELETE(util_vbuf);
|
||||
}
|
||||
|
||||
void SetPointCopySampler()
|
||||
{
|
||||
D3D::context->PSSetSamplers(0, 1, &point_copy_sampler);
|
||||
}
|
||||
|
||||
void SetLinearCopySampler()
|
||||
{
|
||||
D3D::context->PSSetSamplers(0, 1, &linear_copy_sampler);
|
||||
}
|
||||
|
||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
|
||||
const D3D11_RECT* rSource,
|
||||
int SourceWidth,
|
||||
int SourceHeight,
|
||||
ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* Vshader,
|
||||
ID3D11InputLayout* layout,
|
||||
float Gamma)
|
||||
{
|
||||
float sw = 1.0f /(float) SourceWidth;
|
||||
float sh = 1.0f /(float) SourceHeight;
|
||||
float u1 = ((float)rSource->left) * sw;
|
||||
float u2 = ((float)rSource->right) * sw;
|
||||
float v1 = ((float)rSource->top) * sh;
|
||||
float v2 = ((float)rSource->bottom) * sh;
|
||||
float G = 1.0f / Gamma;
|
||||
|
||||
STQVertex coords[4] = {
|
||||
{-1.0f, 1.0f, 0.0f, u1, v1, G},
|
||||
{ 1.0f, 1.0f, 0.0f, u2, v1, G},
|
||||
{-1.0f,-1.0f, 0.0f, u1, v2, G},
|
||||
{ 1.0f,-1.0f, 0.0f, u2, v2, G},
|
||||
};
|
||||
|
||||
// only upload the data to VRAM if it changed
|
||||
if (stq_observer ||
|
||||
tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 ||
|
||||
tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2 || tex_quad_data.G != G)
|
||||
{
|
||||
stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex));
|
||||
stq_observer = false;
|
||||
|
||||
tex_quad_data.u1 = u1;
|
||||
tex_quad_data.v1 = v1;
|
||||
tex_quad_data.u2 = u2;
|
||||
tex_quad_data.v2 = v2;
|
||||
tex_quad_data.G = G;
|
||||
}
|
||||
UINT stride = sizeof(STQVertex);
|
||||
UINT offset = 0;
|
||||
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
D3D::context->IASetInputLayout(layout);
|
||||
D3D::context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
|
||||
D3D::context->PSSetShader(PShader, NULL, 0);
|
||||
D3D::context->PSSetShaderResources(0, 1, &texture);
|
||||
D3D::context->VSSetShader(Vshader, NULL, 0);
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->Draw(4, stq_offset);
|
||||
|
||||
ID3D11ShaderResourceView* texres = NULL;
|
||||
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
|
||||
}
|
||||
|
||||
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
||||
const MathUtil::Rectangle<float>* rSource,
|
||||
int SourceWidth,
|
||||
int SourceHeight,
|
||||
const MathUtil::Rectangle<float>* rDest,
|
||||
ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* Vshader,
|
||||
ID3D11InputLayout* layout,
|
||||
float Gamma)
|
||||
{
|
||||
float sw = 1.0f /(float) SourceWidth;
|
||||
float sh = 1.0f /(float) SourceHeight;
|
||||
float u1 = (rSource->left ) * sw;
|
||||
float u2 = (rSource->right ) * sw;
|
||||
float v1 = (rSource->top ) * sh;
|
||||
float v2 = (rSource->bottom) * sh;
|
||||
float G = 1.0f / Gamma;
|
||||
|
||||
STSQVertex coords[4] = {
|
||||
{ rDest->left , rDest->bottom, 0.0f, u1, v2, G},
|
||||
{ rDest->right, rDest->bottom, 0.0f, u2, v2, G},
|
||||
{ rDest->left , rDest->top , 0.0f, u1, v1, G},
|
||||
{ rDest->right, rDest->top , 0.0f, u2, v1, G},
|
||||
};
|
||||
|
||||
// only upload the data to VRAM if it changed
|
||||
if (stsq_observer ||
|
||||
memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(*rDest)) != 0 ||
|
||||
tex_sub_quad_data.u1 != u1 || tex_sub_quad_data.v1 != v1 ||
|
||||
tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2 || tex_sub_quad_data.G != G)
|
||||
{
|
||||
stsq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STSQVertex));
|
||||
stsq_observer = false;
|
||||
|
||||
tex_sub_quad_data.u1 = u1;
|
||||
tex_sub_quad_data.v1 = v1;
|
||||
tex_sub_quad_data.u2 = u2;
|
||||
tex_sub_quad_data.v2 = v2;
|
||||
tex_sub_quad_data.G = G;
|
||||
memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest));
|
||||
}
|
||||
UINT stride = sizeof(STSQVertex);
|
||||
UINT offset = 0;
|
||||
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
|
||||
context->IASetInputLayout(layout);
|
||||
context->PSSetShaderResources(0, 1, &texture);
|
||||
context->PSSetShader(PShader, NULL, 0);
|
||||
context->VSSetShader(Vshader, NULL, 0);
|
||||
stateman->Apply();
|
||||
context->Draw(4, stsq_offset);
|
||||
|
||||
ID3D11ShaderResourceView* texres = NULL;
|
||||
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
|
||||
}
|
||||
|
||||
// Fills a certain area of the current render target with the specified color
|
||||
// destination coordinates normalized to (-1;1)
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
ColVertex coords[4] = {
|
||||
{ x1, y2, 0.f, Color },
|
||||
{ x2, y2, 0.f, Color },
|
||||
{ x1, y1, 0.f, Color },
|
||||
{ x2, y1, 0.f, Color },
|
||||
};
|
||||
|
||||
if(cq_observer ||
|
||||
draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
|
||||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 ||
|
||||
draw_quad_data.col != Color)
|
||||
{
|
||||
cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex));
|
||||
cq_observer = false;
|
||||
|
||||
draw_quad_data.x1 = x1;
|
||||
draw_quad_data.y1 = y1;
|
||||
draw_quad_data.x2 = x2;
|
||||
draw_quad_data.y2 = y2;
|
||||
draw_quad_data.col = Color;
|
||||
}
|
||||
|
||||
context->VSSetShader(VertexShaderCache::GetClearVertexShader(), NULL, 0);
|
||||
context->PSSetShader(PixelShaderCache::GetClearProgram(), NULL, 0);
|
||||
context->IASetInputLayout(VertexShaderCache::GetClearInputLayout());
|
||||
|
||||
UINT stride = sizeof(ColVertex);
|
||||
UINT offset = 0;
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
|
||||
|
||||
stateman->Apply();
|
||||
context->Draw(4, cq_offset);
|
||||
}
|
||||
|
||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout)
|
||||
{
|
||||
ClearVertex coords[4] = {
|
||||
{-1.0f, 1.0f, z, Color},
|
||||
{ 1.0f, 1.0f, z, Color},
|
||||
{-1.0f, -1.0f, z, Color},
|
||||
{ 1.0f, -1.0f, z, Color},
|
||||
};
|
||||
|
||||
if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z)
|
||||
{
|
||||
clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex));
|
||||
clearq_observer = false;
|
||||
|
||||
clear_quad_data.col = Color;
|
||||
clear_quad_data.z = z;
|
||||
}
|
||||
context->VSSetShader(Vshader, NULL, 0);
|
||||
context->PSSetShader(PShader, NULL, 0);
|
||||
context->IASetInputLayout(layout);
|
||||
|
||||
UINT stride = sizeof(ClearVertex);
|
||||
UINT offset = 0;
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
|
||||
stateman->Apply();
|
||||
context->Draw(4, clearq_offset);
|
||||
}
|
||||
|
||||
} // namespace D3D
|
||||
|
||||
} // namespace DX11
|
||||
77
Source/Core/VideoBackends/D3D/Src/D3DUtil.h
Normal file
77
Source/Core/VideoBackends/D3D/Src/D3DUtil.h
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <MathUtil.h>
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
// Font creation flags
|
||||
#define D3DFONT_BOLD 0x0001
|
||||
#define D3DFONT_ITALIC 0x0002
|
||||
|
||||
// Font rendering flags
|
||||
#define D3DFONT_CENTERED 0x0001
|
||||
|
||||
class CD3DFont
|
||||
{
|
||||
ID3D11ShaderResourceView* m_pTexture;
|
||||
ID3D11Buffer* m_pVB;
|
||||
ID3D11InputLayout* m_InputLayout;
|
||||
ID3D11PixelShader* m_pshader;
|
||||
ID3D11VertexShader* m_vshader;
|
||||
ID3D11BlendState* m_blendstate;
|
||||
ID3D11RasterizerState* m_raststate;
|
||||
const int m_dwTexWidth;
|
||||
const int m_dwTexHeight;
|
||||
unsigned int m_LineHeight;
|
||||
float m_fTexCoords[128-32][4];
|
||||
|
||||
public:
|
||||
CD3DFont();
|
||||
// 2D text drawing function
|
||||
// Initializing and destroying device-dependent objects
|
||||
int Init();
|
||||
int Shutdown();
|
||||
int DrawTextScaled(float x, float y,
|
||||
float size,
|
||||
float spacing, u32 dwColor,
|
||||
const char* strText);
|
||||
};
|
||||
|
||||
extern CD3DFont font;
|
||||
|
||||
void InitUtils();
|
||||
void ShutdownUtils();
|
||||
|
||||
void SetPointCopySampler();
|
||||
void SetLinearCopySampler();
|
||||
|
||||
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
|
||||
const D3D11_RECT* rSource,
|
||||
int SourceWidth,
|
||||
int SourceHeight,
|
||||
ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* VShader,
|
||||
ID3D11InputLayout* layout,
|
||||
float Gamma = 1.0f);
|
||||
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
||||
const MathUtil::Rectangle<float>* rSource,
|
||||
int SourceWidth,
|
||||
int SourceHeight,
|
||||
const MathUtil::Rectangle<float>* rDest,
|
||||
ID3D11PixelShader* PShader,
|
||||
ID3D11VertexShader* Vshader,
|
||||
ID3D11InputLayout* layout,
|
||||
float Gamma = 1.0f);
|
||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout);
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2);
|
||||
}
|
||||
|
||||
}
|
||||
218
Source/Core/VideoBackends/D3D/Src/FramebufferManager.cpp
Normal file
218
Source/Core/VideoBackends/D3D/Src/FramebufferManager.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DUtil.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "Render.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "XFBEncoder.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
static XFBEncoder s_xfbEncoder;
|
||||
|
||||
FramebufferManager::Efb FramebufferManager::m_efb;
|
||||
|
||||
D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; }
|
||||
ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; }
|
||||
|
||||
D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; }
|
||||
D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; }
|
||||
ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; }
|
||||
|
||||
D3DTexture2D* &FramebufferManager::GetResolvedEFBColorTexture()
|
||||
{
|
||||
if (g_ActiveConfig.iMultisampleMode)
|
||||
{
|
||||
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), 0, m_efb.color_tex->GetTex(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
return m_efb.resolved_color_tex;
|
||||
}
|
||||
else
|
||||
return m_efb.color_tex;
|
||||
}
|
||||
|
||||
D3DTexture2D* &FramebufferManager::GetResolvedEFBDepthTexture()
|
||||
{
|
||||
if (g_ActiveConfig.iMultisampleMode)
|
||||
{
|
||||
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), 0, m_efb.color_tex->GetTex(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
return m_efb.resolved_color_tex;
|
||||
}
|
||||
else
|
||||
return m_efb.depth_tex;
|
||||
}
|
||||
|
||||
FramebufferManager::FramebufferManager()
|
||||
{
|
||||
unsigned int target_width = Renderer::GetTargetWidth();
|
||||
unsigned int target_height = Renderer::GetTargetHeight();
|
||||
DXGI_SAMPLE_DESC sample_desc = D3D::GetAAMode(g_ActiveConfig.iMultisampleMode);
|
||||
|
||||
ID3D11Texture2D* buf;
|
||||
D3D11_TEXTURE2D_DESC texdesc;
|
||||
HRESULT hr;
|
||||
|
||||
// EFB color texture - primary render target
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
CHECK(hr==S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
||||
m_efb.color_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1));
|
||||
CHECK(m_efb.color_tex!=NULL, "create EFB color texture (size: %dx%d)", target_width, target_height);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view");
|
||||
|
||||
// Temporary EFB color texture - used in ReinterpretPixelData
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
CHECK(hr==S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
||||
m_efb.color_temp_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1));
|
||||
CHECK(m_efb.color_temp_tex!=NULL, "create EFB color temp texture (size: %dx%d)", target_width, target_height);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(), "EFB color temp texture");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(), "EFB color temp texture shader resource view");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view");
|
||||
|
||||
// AccessEFB - Sysmem buffer used to retrieve the pixel data from color_tex
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.color_staging_buf);
|
||||
CHECK(hr==S_OK, "create EFB color staging buffer (hr=%#x)", hr);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)");
|
||||
|
||||
// EFB depth buffer - primary depth buffer
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
||||
m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE), DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1));
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view");
|
||||
|
||||
// Render buffer for AccessEFB (depth data)
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr);
|
||||
m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)");
|
||||
|
||||
// AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.depth_staging_buf);
|
||||
CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)");
|
||||
|
||||
if (g_ActiveConfig.iMultisampleMode)
|
||||
{
|
||||
// Framebuffer resolve textures (color+depth)
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
m_efb.resolved_color_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
CHECK(m_efb.resolved_color_tex!=NULL, "create EFB color resolve texture (size: %dx%d)", target_width, target_height);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetSRV(), "EFB color resolve texture shader resource view");
|
||||
|
||||
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE);
|
||||
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
|
||||
CHECK(hr==S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
||||
m_efb.resolved_depth_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R24_UNORM_X8_TYPELESS);
|
||||
SAFE_RELEASE(buf);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetSRV(), "EFB depth resolve texture shader resource view");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_efb.resolved_color_tex = NULL;
|
||||
m_efb.resolved_depth_tex = NULL;
|
||||
}
|
||||
|
||||
s_xfbEncoder.Init();
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
s_xfbEncoder.Shutdown();
|
||||
|
||||
SAFE_RELEASE(m_efb.color_tex);
|
||||
SAFE_RELEASE(m_efb.color_temp_tex);
|
||||
SAFE_RELEASE(m_efb.color_staging_buf);
|
||||
SAFE_RELEASE(m_efb.resolved_color_tex);
|
||||
SAFE_RELEASE(m_efb.depth_tex);
|
||||
SAFE_RELEASE(m_efb.depth_staging_buf);
|
||||
SAFE_RELEASE(m_efb.depth_read_texture);
|
||||
SAFE_RELEASE(m_efb.resolved_depth_tex);
|
||||
}
|
||||
|
||||
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
|
||||
{
|
||||
u8* dst = Memory::GetPointer(xfbAddr);
|
||||
s_xfbEncoder.Encode(dst, fbWidth, fbHeight, sourceRc, Gamma);
|
||||
}
|
||||
|
||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
||||
{
|
||||
return new XFBSource(D3DTexture2D::Create(target_width, target_height,
|
||||
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE),
|
||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM));
|
||||
}
|
||||
|
||||
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)
|
||||
{
|
||||
TargetRectangle targetSource;
|
||||
|
||||
targetSource.top = ScaleToVirtualXfbHeight(sourceRc.top, Renderer::GetBackbufferHeight());
|
||||
targetSource.bottom = ScaleToVirtualXfbHeight(sourceRc.bottom, Renderer::GetBackbufferHeight());
|
||||
targetSource.left = ScaleToVirtualXfbWidth(sourceRc.left, Renderer::GetBackbufferWidth());
|
||||
targetSource.right = ScaleToVirtualXfbWidth(sourceRc.right, Renderer::GetBackbufferWidth());
|
||||
|
||||
*width = targetSource.right - targetSource.left;
|
||||
*height = targetSource.bottom - targetSource.top;
|
||||
}
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
|
||||
{
|
||||
D3D::drawShadedTexSubQuad(tex->GetSRV(), &sourcerc,
|
||||
texWidth, texHeight, &drawrc, PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
|
||||
}
|
||||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// DX11's XFB decoder does not use this function.
|
||||
// YUYV data is decoded in Render::Swap.
|
||||
}
|
||||
|
||||
void XFBSource::CopyEFB(float Gamma)
|
||||
{
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// Copy EFB data to XFB and restore render target again
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
|
||||
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL);
|
||||
D3D::SetLinearCopySampler();
|
||||
|
||||
D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), sourceRc.AsRECT(),
|
||||
Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
|
||||
PixelShaderCache::GetColorCopyProgram(true), VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(),Gamma);
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
|
||||
FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
109
Source/Core/VideoBackends/D3D/Src/FramebufferManager.h
Normal file
109
Source/Core/VideoBackends/D3D/Src/FramebufferManager.h
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _FBMANAGER_D3D_H_
|
||||
#define _FBMANAGER_D3D_H_
|
||||
|
||||
#include "d3d11.h"
|
||||
|
||||
#include "FramebufferManagerBase.h"
|
||||
|
||||
#include "D3DTexture.h"
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
// On the GameCube, the game sends a request for the graphics processor to
|
||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
||||
// decided at the time of the copy, and the format is always YUYV. The video
|
||||
// interface is given a pointer to the XFB, which will be decoded and
|
||||
// displayed on the TV.
|
||||
//
|
||||
// There are two ways for Dolphin to emulate this:
|
||||
//
|
||||
// Real XFB mode:
|
||||
//
|
||||
// Dolphin will behave like the GameCube and encode the EFB to
|
||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
||||
// for output to the screen.
|
||||
//
|
||||
// Advantages: Behaves exactly like the GameCube.
|
||||
// Disadvantages: Resolution will be limited.
|
||||
//
|
||||
// Virtual XFB mode:
|
||||
//
|
||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
||||
// The video interface will look up the XFB in the list and use the enhanced
|
||||
// data stored there, if available.
|
||||
//
|
||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
||||
|
||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
||||
// virtualize.
|
||||
|
||||
struct XFBSource : public XFBSourceBase
|
||||
{
|
||||
XFBSource(D3DTexture2D *_tex) : tex(_tex) {}
|
||||
~XFBSource() { tex->Release(); }
|
||||
|
||||
void Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
void CopyEFB(float Gamma);
|
||||
|
||||
D3DTexture2D* const tex;
|
||||
};
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
FramebufferManager();
|
||||
~FramebufferManager();
|
||||
|
||||
static D3DTexture2D* &GetEFBColorTexture();
|
||||
static ID3D11Texture2D* &GetEFBColorStagingBuffer();
|
||||
|
||||
static D3DTexture2D* &GetEFBDepthTexture();
|
||||
static D3DTexture2D* &GetEFBDepthReadTexture();
|
||||
static ID3D11Texture2D* &GetEFBDepthStagingBuffer();
|
||||
|
||||
static D3DTexture2D* &GetResolvedEFBColorTexture();
|
||||
static D3DTexture2D* &GetResolvedEFBDepthTexture();
|
||||
|
||||
static D3DTexture2D* &GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
|
||||
static void SwapReinterpretTexture()
|
||||
{
|
||||
D3DTexture2D* swaptex = GetEFBColorTempTexture();
|
||||
m_efb.color_temp_tex = GetEFBColorTexture();
|
||||
m_efb.color_tex = swaptex;
|
||||
}
|
||||
|
||||
private:
|
||||
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
||||
void GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc);
|
||||
|
||||
void CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma);
|
||||
|
||||
static struct Efb
|
||||
{
|
||||
D3DTexture2D* color_tex;
|
||||
ID3D11Texture2D* color_staging_buf;
|
||||
|
||||
D3DTexture2D* depth_tex;
|
||||
ID3D11Texture2D* depth_staging_buf;
|
||||
D3DTexture2D* depth_read_texture;
|
||||
|
||||
D3DTexture2D* color_temp_tex;
|
||||
|
||||
D3DTexture2D* resolved_color_tex;
|
||||
D3DTexture2D* resolved_depth_tex;
|
||||
} m_efb;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
#endif
|
||||
80
Source/Core/VideoBackends/D3D/Src/GfxState.cpp
Normal file
80
Source/Core/VideoBackends/D3D/Src/GfxState.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "GfxState.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
StateManager* stateman;
|
||||
|
||||
|
||||
template<typename T> AutoState<T>::AutoState(const T* object) : state(object)
|
||||
{
|
||||
((IUnknown*)state)->AddRef();
|
||||
}
|
||||
|
||||
template<typename T> AutoState<T>::AutoState(const AutoState<T> &source)
|
||||
{
|
||||
state = source.GetPtr();
|
||||
((T*)state)->AddRef();
|
||||
}
|
||||
|
||||
template<typename T> AutoState<T>::~AutoState()
|
||||
{
|
||||
if(state) ((T*)state)->Release();
|
||||
state = NULL;
|
||||
}
|
||||
|
||||
StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {}
|
||||
|
||||
void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); }
|
||||
void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); }
|
||||
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); }
|
||||
void StateManager::PopBlendState() { blendstates.pop(); }
|
||||
void StateManager::PopDepthState() { depthstates.pop(); }
|
||||
void StateManager::PopRasterizerState() { raststates.pop(); }
|
||||
|
||||
void StateManager::Apply()
|
||||
{
|
||||
if (!blendstates.empty())
|
||||
{
|
||||
if (cur_blendstate != blendstates.top().GetPtr())
|
||||
{
|
||||
cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr();
|
||||
D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
else ERROR_LOG(VIDEO, "Tried to apply without blend state!");
|
||||
|
||||
if (!depthstates.empty())
|
||||
{
|
||||
if (cur_depthstate != depthstates.top().GetPtr())
|
||||
{
|
||||
cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr();
|
||||
D3D::context->OMSetDepthStencilState(cur_depthstate, 0);
|
||||
}
|
||||
}
|
||||
else ERROR_LOG(VIDEO, "Tried to apply without depth state!");
|
||||
|
||||
if (!raststates.empty())
|
||||
{
|
||||
if (cur_raststate != raststates.top().GetPtr())
|
||||
{
|
||||
cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr();
|
||||
D3D::context->RSSetState(cur_raststate);
|
||||
}
|
||||
}
|
||||
else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX11
|
||||
67
Source/Core/VideoBackends/D3D/Src/GfxState.h
Normal file
67
Source/Core/VideoBackends/D3D/Src/GfxState.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stack>
|
||||
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
template<typename T> class AutoState
|
||||
{
|
||||
public:
|
||||
AutoState(const T* object);
|
||||
AutoState(const AutoState<T> &source);
|
||||
~AutoState();
|
||||
|
||||
const inline T* GetPtr() const { return state; }
|
||||
|
||||
private:
|
||||
const T* state;
|
||||
};
|
||||
|
||||
typedef AutoState<ID3D11BlendState> AutoBlendState;
|
||||
typedef AutoState<ID3D11DepthStencilState> AutoDepthStencilState;
|
||||
typedef AutoState<ID3D11RasterizerState> AutoRasterizerState;
|
||||
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
StateManager();
|
||||
|
||||
// call any of these to change the affected states
|
||||
void PushBlendState(const ID3D11BlendState* state);
|
||||
void PushDepthState(const ID3D11DepthStencilState* state);
|
||||
void PushRasterizerState(const ID3D11RasterizerState* state);
|
||||
|
||||
// call these after drawing
|
||||
void PopBlendState();
|
||||
void PopDepthState();
|
||||
void PopRasterizerState();
|
||||
|
||||
// call this before any drawing operation if states could have changed meanwhile
|
||||
void Apply();
|
||||
|
||||
private:
|
||||
std::stack<AutoBlendState> blendstates;
|
||||
std::stack<AutoDepthStencilState> depthstates;
|
||||
std::stack<AutoRasterizerState> raststates;
|
||||
ID3D11BlendState* cur_blendstate;
|
||||
ID3D11DepthStencilState* cur_depthstate;
|
||||
ID3D11RasterizerState* cur_raststate;
|
||||
};
|
||||
|
||||
extern StateManager* stateman;
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX11
|
||||
14
Source/Core/VideoBackends/D3D/Src/Globals.h
Normal file
14
Source/Core/VideoBackends/D3D/Src/Globals.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _GLOBALS_H_
|
||||
#define _GLOBALS_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
#endif // _GLOBALS_H_
|
||||
238
Source/Core/VideoBackends/D3D/Src/LineGeometryShader.cpp
Normal file
238
Source/Core/VideoBackends/D3D/Src/LineGeometryShader.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "LineGeometryShader.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
struct LineGSParams
|
||||
{
|
||||
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
FLOAT VpWidth; // Width and height of the viewport in EFB pixels
|
||||
FLOAT VpHeight;
|
||||
FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off)
|
||||
};
|
||||
|
||||
union LineGSParams_Padded
|
||||
{
|
||||
LineGSParams params;
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[(sizeof(LineGSParams) + 15) & ~15];
|
||||
};
|
||||
|
||||
static const char LINE_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu line geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match LineGSParams above
|
||||
"{\n"
|
||||
"float LineWidth;\n"
|
||||
"float TexOffset;\n"
|
||||
"float VpWidth;\n"
|
||||
"float VpHeight;\n"
|
||||
"float TexOffsetEnable[8];\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
// Pretend input[0] is on the bottom and input[1] is on top.
|
||||
// We generate vertices to the left and right.
|
||||
|
||||
"VS_OUTPUT l0 = input[0];\n"
|
||||
"VS_OUTPUT r0 = l0;\n"
|
||||
"VS_OUTPUT l1 = input[1];\n"
|
||||
"VS_OUTPUT r1 = l1;\n"
|
||||
|
||||
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
|
||||
// use the correct line caps. Instead, the line caps are vertical or
|
||||
// horizontal depending the slope of the line.
|
||||
|
||||
"float2 offset;\n"
|
||||
"float2 to = abs(input[1].pos.xy - input[0].pos.xy);\n"
|
||||
// FIXME: What does real hardware do when line is at a 45-degree angle?
|
||||
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
|
||||
"if (Params.VpHeight*to.y > Params.VpWidth*to.x) {\n"
|
||||
// Line is more tall. Extend geometry left and right.
|
||||
// Lerp Params.LineWidth/2 from [0..VpWidth] to [-1..1]
|
||||
"offset = float2(Params.LineWidth/Params.VpWidth, 0);\n"
|
||||
"} else {\n"
|
||||
// Line is more wide. Extend geometry up and down.
|
||||
// Lerp Params.LineWidth/2 from [0..VpHeight] to [1..-1]
|
||||
"offset = float2(0, -Params.LineWidth/Params.VpHeight);\n"
|
||||
"}\n"
|
||||
|
||||
"l0.pos.xy -= offset * input[0].pos.w;\n"
|
||||
"r0.pos.xy += offset * input[0].pos.w;\n"
|
||||
"l1.pos.xy -= offset * input[1].pos.w;\n"
|
||||
"r1.pos.xy += offset * input[1].pos.w;\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex.
|
||||
// They can each be enabled seperately.
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"r0.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n"
|
||||
"r1.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"r0.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n"
|
||||
"r1.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"r0.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n"
|
||||
"r1.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"r0.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n"
|
||||
"r1.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"r0.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n"
|
||||
"r1.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"r0.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n"
|
||||
"r1.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"r0.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n"
|
||||
"r1.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"r0.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n"
|
||||
"r1.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(l0);\n"
|
||||
"outStream.Append(r0);\n"
|
||||
"outStream.Append(l1);\n"
|
||||
"outStream.Append(r1);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
LineGeometryShader::LineGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void LineGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams_Padded),
|
||||
D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void LineGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool LineGeometryShader::SetShader(u32 components, float lineWidth,
|
||||
float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char buffer[16384];
|
||||
ShaderCode code;
|
||||
code.SetBuffer(buffer);
|
||||
GenerateVSOutputStructForGS(code, components, API_D3D);
|
||||
code.Write("\n%s", LINE_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStream;
|
||||
numTexCoordsStream << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
const std::string& numTexCoordsStr = numTexCoordsStream.str();
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
LineGSParams* params = (LineGSParams*)map.pData;
|
||||
params->LineWidth = lineWidth;
|
||||
|
||||
params->TexOffset = texOffset;
|
||||
params->VpWidth = vpWidth;
|
||||
params->VpHeight = vpHeight;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f;
|
||||
|
||||
D3D::context->Unmap(m_paramsBuffer, 0);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Failed to map line gs params buffer");
|
||||
|
||||
DEBUG_LOG(VIDEO, "Line params: width %f, texOffset %f, vpWidth %f, vpHeight %f",
|
||||
lineWidth, texOffset, vpWidth, vpHeight);
|
||||
|
||||
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
|
||||
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
45
Source/Core/VideoBackends/D3D/Src/LineGeometryShader.h
Normal file
45
Source/Core/VideoBackends/D3D/Src/LineGeometryShader.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _LINEGEOMETRYSHADER_H
|
||||
#define _LINEGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of line geometry shaders, one for each
|
||||
// vertex format.
|
||||
class LineGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LineGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float lineWidth, float texOffset,
|
||||
float vpWidth, float vpHeight, const bool* texOffsetEnable);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
143
Source/Core/VideoBackends/D3D/Src/NativeVertexFormat.cpp
Normal file
143
Source/Core/VideoBackends/D3D/Src/NativeVertexFormat.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DBlob.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class D3DVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC m_elems[32];
|
||||
UINT m_num_elems;
|
||||
|
||||
DX11::D3DBlob* m_vs_bytecode;
|
||||
ID3D11InputLayout* m_layout;
|
||||
|
||||
public:
|
||||
D3DVertexFormat() : m_num_elems(0), m_vs_bytecode(NULL), m_layout(NULL) {}
|
||||
~D3DVertexFormat() { SAFE_RELEASE(m_vs_bytecode); SAFE_RELEASE(m_layout); }
|
||||
|
||||
void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
||||
void SetupVertexPointers();
|
||||
};
|
||||
|
||||
NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
|
||||
{
|
||||
return new D3DVertexFormat();
|
||||
}
|
||||
|
||||
DXGI_FORMAT VarToD3D(VarType t, int size)
|
||||
{
|
||||
DXGI_FORMAT retval = DXGI_FORMAT_UNKNOWN;
|
||||
static const DXGI_FORMAT lookup1[5] = {
|
||||
DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R32_FLOAT
|
||||
};
|
||||
static const DXGI_FORMAT lookup2[5] = {
|
||||
DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R32G32_FLOAT
|
||||
};
|
||||
static const DXGI_FORMAT lookup3[5] = {
|
||||
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT
|
||||
};
|
||||
static const DXGI_FORMAT lookup4[5] = {
|
||||
DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R32G32B32A32_FLOAT
|
||||
};
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1: retval = lookup1[t]; break;
|
||||
case 2: retval = lookup2[t]; break;
|
||||
case 3: retval = lookup3[t]; break;
|
||||
case 4: retval = lookup4[t]; break;
|
||||
default: break;
|
||||
}
|
||||
if (retval == DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
||||
{
|
||||
vertex_stride = _vtx_decl.stride;
|
||||
memset(m_elems, 0, sizeof(m_elems));
|
||||
|
||||
m_elems[m_num_elems].SemanticName = "POSITION";
|
||||
m_elems[m_num_elems].AlignedByteOffset = 0;
|
||||
m_elems[m_num_elems].Format = DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
++m_num_elems;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (_vtx_decl.normal_offset[i] > 0)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "NORMAL";
|
||||
m_elems[m_num_elems].SemanticIndex = i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.normal_offset[i];
|
||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
++m_num_elems;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (_vtx_decl.color_offset[i] > 0)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "COLOR";
|
||||
m_elems[m_num_elems].SemanticIndex = i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.color_offset[i];
|
||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.color_gl_type, 4);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
++m_num_elems;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (_vtx_decl.texcoord_offset[i] > 0)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "TEXCOORD";
|
||||
m_elems[m_num_elems].SemanticIndex = i;
|
||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.texcoord_offset[i];
|
||||
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]);
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
++m_num_elems;
|
||||
}
|
||||
}
|
||||
|
||||
if (_vtx_decl.posmtx_offset != -1)
|
||||
{
|
||||
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
|
||||
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.posmtx_offset;
|
||||
m_elems[m_num_elems].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
++m_num_elems;
|
||||
}
|
||||
}
|
||||
|
||||
void D3DVertexFormat::SetupVertexPointers()
|
||||
{
|
||||
if (m_vs_bytecode != DX11::VertexShaderCache::GetActiveShaderBytecode())
|
||||
{
|
||||
SAFE_RELEASE(m_vs_bytecode);
|
||||
SAFE_RELEASE(m_layout);
|
||||
|
||||
m_vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode();
|
||||
m_vs_bytecode->AddRef();
|
||||
|
||||
HRESULT hr = DX11::D3D::device->CreateInputLayout(m_elems, m_num_elems, m_vs_bytecode->Data(), m_vs_bytecode->Size(), &m_layout);
|
||||
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
||||
DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout, "input layout used to emulate the GX pipeline");
|
||||
}
|
||||
DX11::D3D::context->IASetInputLayout(m_layout);
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
1449
Source/Core/VideoBackends/D3D/Src/PSTextureEncoder.cpp
Normal file
1449
Source/Core/VideoBackends/D3D/Src/PSTextureEncoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
106
Source/Core/VideoBackends/D3D/Src/PSTextureEncoder.h
Normal file
106
Source/Core/VideoBackends/D3D/Src/PSTextureEncoder.h
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _PSTEXTUREENCODER_H
|
||||
#define _PSTEXTUREENCODER_H
|
||||
|
||||
#include "TextureEncoder.h"
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11RenderTargetView;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11InputLayout;
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11ClassLinkage;
|
||||
struct ID3D11ClassInstance;
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
struct ID3D11SamplerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class PSTextureEncoder : public TextureEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
PSTextureEncoder();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
size_t Encode(u8* dst, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect, bool isIntensity,
|
||||
bool scaleByHalf);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Texture2D* m_out;
|
||||
ID3D11RenderTargetView* m_outRTV;
|
||||
ID3D11Texture2D* m_outStage;
|
||||
ID3D11Buffer* m_encodeParams;
|
||||
ID3D11Buffer* m_quad;
|
||||
ID3D11VertexShader* m_vShader;
|
||||
ID3D11InputLayout* m_quadLayout;
|
||||
ID3D11BlendState* m_efbEncodeBlendState;
|
||||
ID3D11DepthStencilState* m_efbEncodeDepthState;
|
||||
ID3D11RasterizerState* m_efbEncodeRastState;
|
||||
ID3D11SamplerState* m_efbSampler;
|
||||
|
||||
// Stuff only used in static-linking mode (SM4.0-compatible)
|
||||
|
||||
bool InitStaticMode();
|
||||
bool SetStaticShader(unsigned int dstFormat, unsigned int srcFormat,
|
||||
bool isIntensity, bool scaleByHalf);
|
||||
|
||||
typedef unsigned int ComboKey; // Key for a shader combination
|
||||
|
||||
ComboKey MakeComboKey(unsigned int dstFormat, unsigned int srcFormat,
|
||||
bool isIntensity, bool scaleByHalf)
|
||||
{
|
||||
return (dstFormat << 4) | (srcFormat << 2) | (isIntensity ? (1<<1) : 0)
|
||||
| (scaleByHalf ? (1<<0) : 0);
|
||||
}
|
||||
|
||||
typedef std::map<ComboKey, ID3D11PixelShader*> ComboMap;
|
||||
|
||||
ComboMap m_staticShaders;
|
||||
|
||||
// Stuff only used for dynamic-linking mode (SM5.0+, available as soon as
|
||||
// Microsoft fixes their bloody HLSL compiler)
|
||||
|
||||
bool InitDynamicMode();
|
||||
bool SetDynamicShader(unsigned int dstFormat, unsigned int srcFormat,
|
||||
bool isIntensity, bool scaleByHalf);
|
||||
|
||||
ID3D11PixelShader* m_dynamicShader;
|
||||
ID3D11ClassLinkage* m_classLinkage;
|
||||
|
||||
// Interface slots
|
||||
UINT m_fetchSlot;
|
||||
UINT m_scaledFetchSlot;
|
||||
UINT m_intensitySlot;
|
||||
UINT m_generatorSlot;
|
||||
|
||||
// Class instances
|
||||
// Fetch: 0 is RGB, 1 is RGBA, 2 is RGB565, 3 is Z
|
||||
ID3D11ClassInstance* m_fetchClass[4];
|
||||
// ScaledFetch: 0 is off, 1 is on
|
||||
ID3D11ClassInstance* m_scaledFetchClass[2];
|
||||
// Intensity: 0 is off, 1 is on
|
||||
ID3D11ClassInstance* m_intensityClass[2];
|
||||
// Generator: one for each dst format, 16 total
|
||||
ID3D11ClassInstance* m_generatorClass[16];
|
||||
|
||||
std::vector<ID3D11ClassInstance*> m_linkageArray;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
171
Source/Core/VideoBackends/D3D/Src/PerfQuery.cpp
Normal file
171
Source/Core/VideoBackends/D3D/Src/PerfQuery.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "PerfQuery.h"
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
PerfQuery::PerfQuery()
|
||||
: m_query_read_pos()
|
||||
, m_query_count()
|
||||
{
|
||||
for (int i = 0; i != ArraySize(m_query_buffer); ++i)
|
||||
{
|
||||
D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
|
||||
D3D::device->CreateQuery(&qdesc, &m_query_buffer[i].query);
|
||||
}
|
||||
ResetQuery();
|
||||
}
|
||||
|
||||
PerfQuery::~PerfQuery()
|
||||
{
|
||||
for (int i = 0; i != ArraySize(m_query_buffer); ++i)
|
||||
{
|
||||
// TODO: EndQuery?
|
||||
m_query_buffer[i].query->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::EnableQuery(PerfQueryGroup type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
// Is this sane?
|
||||
if (m_query_count > ArraySize(m_query_buffer) / 2)
|
||||
WeakFlush();
|
||||
|
||||
if (ArraySize(m_query_buffer) == m_query_count)
|
||||
{
|
||||
// TODO
|
||||
FlushOne();
|
||||
ERROR_LOG(VIDEO, "Flushed query buffer early!");
|
||||
}
|
||||
|
||||
// start query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ArraySize(m_query_buffer)];
|
||||
|
||||
D3D::context->Begin(entry.query);
|
||||
entry.query_type = type;
|
||||
|
||||
++m_query_count;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::DisableQuery(PerfQueryGroup type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
// stop query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + ArraySize(m_query_buffer)-1) % ArraySize(m_query_buffer)];
|
||||
D3D::context->End(entry.query);
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::ResetQuery()
|
||||
{
|
||||
m_query_count = 0;
|
||||
std::fill_n(m_results, ArraySize(m_results), 0);
|
||||
}
|
||||
|
||||
u32 PerfQuery::GetQueryResult(PerfQueryType type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return 0;
|
||||
|
||||
u32 result = 0;
|
||||
|
||||
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP];
|
||||
}
|
||||
else if (type == PQ_BLEND_INPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_EFB_COPY_CLOCKS)
|
||||
{
|
||||
result = m_results[PQG_EFB_COPY_CLOCKS];
|
||||
}
|
||||
|
||||
return result / 4;
|
||||
}
|
||||
|
||||
void PerfQuery::FlushOne()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
UINT64 result = 0;
|
||||
HRESULT hr = S_FALSE;
|
||||
while (hr != S_OK)
|
||||
{
|
||||
// TODO: Might cause us to be stuck in an infinite loop!
|
||||
hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0);
|
||||
}
|
||||
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % ArraySize(m_query_buffer);
|
||||
--m_query_count;
|
||||
}
|
||||
|
||||
// TODO: could selectively flush things, but I don't think that will do much
|
||||
void PerfQuery::FlushResults()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
while (!IsFlushed())
|
||||
FlushOne();
|
||||
}
|
||||
|
||||
void PerfQuery::WeakFlush()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
while (!IsFlushed())
|
||||
{
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
UINT64 result = 0;
|
||||
HRESULT hr = D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||
|
||||
if (hr == S_OK)
|
||||
{
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % ArraySize(m_query_buffer);
|
||||
--m_query_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfQuery::IsFlushed() const
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return true;
|
||||
|
||||
return 0 == m_query_count;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
46
Source/Core/VideoBackends/D3D/Src/PerfQuery.h
Normal file
46
Source/Core/VideoBackends/D3D/Src/PerfQuery.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _PERFQUERY_H_
|
||||
#define _PERFQUERY_H_
|
||||
|
||||
#include "PerfQueryBase.h"
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
class PerfQuery : public PerfQueryBase
|
||||
{
|
||||
public:
|
||||
PerfQuery();
|
||||
~PerfQuery();
|
||||
|
||||
void EnableQuery(PerfQueryGroup type);
|
||||
void DisableQuery(PerfQueryGroup type);
|
||||
void ResetQuery();
|
||||
u32 GetQueryResult(PerfQueryType type);
|
||||
void FlushResults();
|
||||
bool IsFlushed() const;
|
||||
|
||||
private:
|
||||
struct ActiveQuery
|
||||
{
|
||||
ID3D11Query* query;
|
||||
PerfQueryGroup query_type;
|
||||
};
|
||||
|
||||
void WeakFlush();
|
||||
|
||||
// Only use when non-empty
|
||||
void FlushOne();
|
||||
|
||||
// when testing in SMS: 64 was too small, 128 was ok
|
||||
static const int PERF_QUERY_BUFFER_SIZE = 512;
|
||||
|
||||
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
|
||||
int m_query_read_pos;
|
||||
|
||||
// TODO: sloppy
|
||||
volatile int m_query_count;
|
||||
volatile u32 m_results[PQG_NUM_MEMBERS];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _PERFQUERY_H_
|
||||
585
Source/Core/VideoBackends/D3D/Src/PixelShaderCache.cpp
Normal file
585
Source/Core/VideoBackends/D3D/Src/PixelShaderCache.cpp
Normal file
@@ -0,0 +1,585 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "LinearDiskCache.h"
|
||||
|
||||
#include "Debugger.h"
|
||||
#include "Statistics.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "Globals.h"
|
||||
#include "PixelShaderGen.h"
|
||||
#include "PixelShaderCache.h"
|
||||
|
||||
#include "ConfigManager.h"
|
||||
|
||||
extern int frameCount;
|
||||
|
||||
// See comment near the bottom of this file.
|
||||
float psconstants[C_PENVCONST_END*4];
|
||||
bool pscbufchanged = true;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
||||
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
|
||||
PixelShaderUid PixelShaderCache::last_uid;
|
||||
UidChecker<PixelShaderUid,PixelShaderCode> PixelShaderCache::pixel_uid_checker;
|
||||
|
||||
LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache;
|
||||
|
||||
ID3D11PixelShader* s_ColorMatrixProgram[2] = {NULL};
|
||||
ID3D11PixelShader* s_ColorCopyProgram[2] = {NULL};
|
||||
ID3D11PixelShader* s_DepthMatrixProgram[2] = {NULL};
|
||||
ID3D11PixelShader* s_ClearProgram = NULL;
|
||||
ID3D11PixelShader* s_rgba6_to_rgb8[2] = {NULL};
|
||||
ID3D11PixelShader* s_rgb8_to_rgba6[2] = {NULL};
|
||||
ID3D11Buffer* pscbuf = NULL;
|
||||
|
||||
const char clear_program_code[] = {
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float4 incol0 : COLOR0){\n"
|
||||
"ocol0 = incol0;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
// TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA...
|
||||
const char color_copy_program_code[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float2 uv0 : TEXCOORD0){\n"
|
||||
"ocol0 = Tex0.Sample(samp0,uv0);\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
// TODO: Improve sampling algorithm!
|
||||
const char color_copy_program_code_msaa[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
"in float2 uv0 : TEXCOORD0){\n"
|
||||
"int width, height, samples;\n"
|
||||
"Tex0.GetDimensions(width, height, samples);\n"
|
||||
"ocol0 = 0;\n"
|
||||
"for(int i = 0; i < samples; ++i)\n"
|
||||
" ocol0 += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
|
||||
"ocol0 /= samples;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char color_matrix_program_code[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"uniform float4 cColMatrix[7] : register(c0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0){\n"
|
||||
"float4 texcol = Tex0.Sample(samp0,uv0);\n"
|
||||
"texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char color_matrix_program_code_msaa[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
|
||||
"uniform float4 cColMatrix[7] : register(c0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
"in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0){\n"
|
||||
"int width, height, samples;\n"
|
||||
"Tex0.GetDimensions(width, height, samples);\n"
|
||||
"float4 texcol = 0;\n"
|
||||
"for(int i = 0; i < samples; ++i)\n"
|
||||
" texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
|
||||
"texcol /= samples;\n"
|
||||
"texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char depth_matrix_program[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"uniform float4 cColMatrix[7] : register(c0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0){\n"
|
||||
"float4 texcol = Tex0.Sample(samp0,uv0);\n"
|
||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,256.0f,256.0f*256.0f,1.0f));\n"
|
||||
"texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * float4(255.0f,255.0f,255.0f,15.0f)) / float4(255.0f,255.0f,255.0f,15.0f);\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char depth_matrix_program_msaa[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
|
||||
"uniform float4 cColMatrix[7] : register(c0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0){\n"
|
||||
"int width, height, samples;\n"
|
||||
"Tex0.GetDimensions(width, height, samples);\n"
|
||||
"float4 texcol = 0;\n"
|
||||
"for(int i = 0; i < samples; ++i)\n"
|
||||
" texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
|
||||
"texcol /= samples;\n"
|
||||
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,256.0f,256.0f*256.0f,16.0f));\n"
|
||||
"texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * float4(255.0f,255.0f,255.0f,15.0f)) / float4(255.0f,255.0f,255.0f,15.0f);\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char reint_rgba6_to_rgb8[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n"
|
||||
" int4 dst8;\n"
|
||||
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
|
||||
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
|
||||
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
|
||||
" dst8.a = 255;\n"
|
||||
" ocol0 = (float4)dst8 / 255.f;\n"
|
||||
"}"
|
||||
};
|
||||
|
||||
const char reint_rgba6_to_rgb8_msaa[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int width, height, samples;\n"
|
||||
" Tex0.GetDimensions(width, height, samples);\n"
|
||||
" float4 texcol = 0;\n"
|
||||
" for(int i = 0; i < samples; ++i)\n"
|
||||
" texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
|
||||
" texcol /= samples;\n"
|
||||
" int4 src6 = round(texcol * 63.f);\n"
|
||||
" int4 dst8;\n"
|
||||
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
|
||||
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
|
||||
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
|
||||
" dst8.a = 255;\n"
|
||||
" ocol0 = (float4)dst8 / 255.f;\n"
|
||||
"}"
|
||||
};
|
||||
|
||||
const char reint_rgb8_to_rgba6[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n"
|
||||
" int4 dst6;\n"
|
||||
" dst6.r = src8.r >> 2;\n"
|
||||
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
|
||||
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
|
||||
" dst6.a = src8.b & 0x3F;\n"
|
||||
" ocol0 = (float4)dst6 / 63.f;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char reint_rgb8_to_rgba6_msaa[] = {
|
||||
"sampler samp0 : register(s0);\n"
|
||||
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
|
||||
"void main(\n"
|
||||
" out float4 ocol0 : SV_Target,\n"
|
||||
" in float4 pos : SV_Position,\n"
|
||||
" in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
" int width, height, samples;\n"
|
||||
" Tex0.GetDimensions(width, height, samples);\n"
|
||||
" float4 texcol = 0;\n"
|
||||
" for(int i = 0; i < samples; ++i)\n"
|
||||
" texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
|
||||
" texcol /= samples;\n"
|
||||
" int4 src8 = round(texcol * 255.f);\n"
|
||||
" int4 dst6;\n"
|
||||
" dst6.r = src8.r >> 2;\n"
|
||||
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
|
||||
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
|
||||
" dst6.a = src8.b & 0x3F;\n"
|
||||
" ocol0 = (float4)dst6 / 63.f;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::ReinterpRGBA6ToRGB8(bool multisampled)
|
||||
{
|
||||
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1)
|
||||
{
|
||||
if (!s_rgba6_to_rgb8[0])
|
||||
{
|
||||
s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8, sizeof(reint_rgba6_to_rgb8));
|
||||
CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader");
|
||||
}
|
||||
return s_rgba6_to_rgb8[0];
|
||||
}
|
||||
else if (!s_rgba6_to_rgb8[1])
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
char buf[1024];
|
||||
const int l = sprintf_s(buf, 1024, reint_rgba6_to_rgb8_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
|
||||
|
||||
s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf, l);
|
||||
|
||||
CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader");
|
||||
}
|
||||
return s_rgba6_to_rgb8[1];
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::ReinterpRGB8ToRGBA6(bool multisampled)
|
||||
{
|
||||
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1)
|
||||
{
|
||||
if (!s_rgb8_to_rgba6[0])
|
||||
{
|
||||
s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6, sizeof(reint_rgb8_to_rgba6));
|
||||
CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader");
|
||||
}
|
||||
return s_rgb8_to_rgba6[0];
|
||||
}
|
||||
else if (!s_rgb8_to_rgba6[1])
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
char buf[1024];
|
||||
const int l = sprintf_s(buf, 1024, reint_rgb8_to_rgba6_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
|
||||
|
||||
s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf, l);
|
||||
|
||||
CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader");
|
||||
D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader");
|
||||
}
|
||||
return s_rgb8_to_rgba6[1];
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram(bool multisampled)
|
||||
{
|
||||
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_ColorCopyProgram[0];
|
||||
else if (s_ColorCopyProgram[1]) return s_ColorCopyProgram[1];
|
||||
else
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
char buf[1024];
|
||||
int l = sprintf_s(buf, 1024, color_copy_program_code_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
|
||||
s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
|
||||
CHECK(s_ColorCopyProgram[1]!=NULL, "Create color copy MSAA pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[1], "color copy MSAA pixel shader");
|
||||
return s_ColorCopyProgram[1];
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram(bool multisampled)
|
||||
{
|
||||
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_ColorMatrixProgram[0];
|
||||
else if (s_ColorMatrixProgram[1]) return s_ColorMatrixProgram[1];
|
||||
else
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
char buf[1024];
|
||||
int l = sprintf_s(buf, 1024, color_matrix_program_code_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
|
||||
s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
|
||||
CHECK(s_ColorMatrixProgram[1]!=NULL, "Create color matrix MSAA pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[1], "color matrix MSAA pixel shader");
|
||||
return s_ColorMatrixProgram[1];
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram(bool multisampled)
|
||||
{
|
||||
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_DepthMatrixProgram[0];
|
||||
else if (s_DepthMatrixProgram[1]) return s_DepthMatrixProgram[1];
|
||||
else
|
||||
{
|
||||
// create MSAA shader for current AA mode
|
||||
char buf[1024];
|
||||
int l = sprintf_s(buf, 1024, depth_matrix_program_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
|
||||
s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
|
||||
CHECK(s_DepthMatrixProgram[1]!=NULL, "Create depth matrix MSAA pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[1], "depth matrix MSAA pixel shader");
|
||||
return s_DepthMatrixProgram[1];
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
|
||||
{
|
||||
return s_ClearProgram;
|
||||
}
|
||||
|
||||
ID3D11Buffer* &PixelShaderCache::GetConstantBuffer()
|
||||
{
|
||||
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
|
||||
if (pscbufchanged)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, psconstants, sizeof(psconstants));
|
||||
D3D::context->Unmap(pscbuf, 0);
|
||||
pscbufchanged = false;
|
||||
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(psconstants));
|
||||
}
|
||||
return pscbuf;
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader<PixelShaderUid, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const PixelShaderUid &key, const u8 *value, u32 value_size)
|
||||
{
|
||||
PixelShaderCache::InsertByteCode(key, value, value_size);
|
||||
}
|
||||
};
|
||||
|
||||
void PixelShaderCache::Init()
|
||||
{
|
||||
unsigned int cbsize = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16
|
||||
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
D3D::device->CreateBuffer(&cbdesc, NULL, &pscbuf);
|
||||
CHECK(pscbuf!=NULL, "Create pixel shader constant buffer");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "pixel shader constant buffer used to emulate the GX pipeline");
|
||||
|
||||
// used when drawing clear quads
|
||||
s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code, sizeof(clear_program_code));
|
||||
CHECK(s_ClearProgram!=NULL, "Create clear pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader");
|
||||
|
||||
// used when copying/resolving the color buffer
|
||||
s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code));
|
||||
CHECK(s_ColorCopyProgram[0]!=NULL, "Create color copy pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[0], "color copy pixel shader");
|
||||
|
||||
// used for color conversion
|
||||
s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code));
|
||||
CHECK(s_ColorMatrixProgram[0]!=NULL, "Create color matrix pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[0], "color matrix pixel shader");
|
||||
|
||||
// used for depth copy
|
||||
s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program));
|
||||
CHECK(s_DepthMatrixProgram[0]!=NULL, "Create depth matrix pixel shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[0], "depth matrix pixel shader");
|
||||
|
||||
Clear();
|
||||
|
||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
|
||||
|
||||
SETSTAT(stats.numPixelShadersCreated, 0);
|
||||
SETSTAT(stats.numPixelShadersAlive, 0);
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
PixelShaderCacheInserter inserter;
|
||||
g_ps_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
|
||||
if (g_Config.bEnableShaderDebugging)
|
||||
Clear();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
// ONLY to be used during shutdown.
|
||||
void PixelShaderCache::Clear()
|
||||
{
|
||||
for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++)
|
||||
iter->second.Destroy();
|
||||
PixelShaders.clear();
|
||||
pixel_uid_checker.Invalidate();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
// Used in Swap() when AA mode has changed
|
||||
void PixelShaderCache::InvalidateMSAAShaders()
|
||||
{
|
||||
SAFE_RELEASE(s_ColorCopyProgram[1]);
|
||||
SAFE_RELEASE(s_ColorMatrixProgram[1]);
|
||||
SAFE_RELEASE(s_DepthMatrixProgram[1]);
|
||||
SAFE_RELEASE(s_rgb8_to_rgba6[1]);
|
||||
SAFE_RELEASE(s_rgba6_to_rgb8[1]);
|
||||
}
|
||||
|
||||
void PixelShaderCache::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(pscbuf);
|
||||
|
||||
SAFE_RELEASE(s_ClearProgram);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
SAFE_RELEASE(s_ColorCopyProgram[i]);
|
||||
SAFE_RELEASE(s_ColorMatrixProgram[i]);
|
||||
SAFE_RELEASE(s_DepthMatrixProgram[i]);
|
||||
SAFE_RELEASE(s_rgba6_to_rgb8[i]);
|
||||
SAFE_RELEASE(s_rgb8_to_rgba6[i]);
|
||||
}
|
||||
|
||||
Clear();
|
||||
g_ps_disk_cache.Sync();
|
||||
g_ps_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
{
|
||||
PixelShaderUid uid;
|
||||
GetPixelShaderUid(uid, dstAlphaMode, API_D3D, components);
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
PixelShaderCode code;
|
||||
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components);
|
||||
pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p");
|
||||
}
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
|
||||
return (last_entry->shader != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
// Check if the shader is already in the cache
|
||||
PSCache::iterator iter;
|
||||
iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end())
|
||||
{
|
||||
const PSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
|
||||
return (entry.shader != NULL);
|
||||
}
|
||||
|
||||
// Need to compile a new shader
|
||||
PixelShaderCode code;
|
||||
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components);
|
||||
|
||||
D3DBlob* pbytecode;
|
||||
if (!D3D::CompilePixelShader(code.GetBuffer(), (unsigned int)strlen(code.GetBuffer()), &pbytecode))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert the bytecode into the caches
|
||||
g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
|
||||
|
||||
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
|
||||
pbytecode->Release();
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging && success)
|
||||
{
|
||||
PixelShaders[uid].code = code.GetBuffer();
|
||||
}
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen)
|
||||
{
|
||||
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
||||
if (shader == NULL)
|
||||
return false;
|
||||
|
||||
// TODO: Somehow make the debug name a bit more specific
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache");
|
||||
|
||||
// Make an entry in the table
|
||||
PSCacheEntry newentry;
|
||||
newentry.shader = shader;
|
||||
PixelShaders[uid] = newentry;
|
||||
last_entry = &PixelShaders[uid];
|
||||
|
||||
if (!shader) {
|
||||
// INCSTAT(stats.numPixelShadersFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
// These are "callbacks" from VideoCommon and thus must be outside namespace DX11.
|
||||
// This will have to be changed when we merge.
|
||||
|
||||
// HACK to avoid some invasive VideoCommon changes
|
||||
// these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something
|
||||
// offset given in floats, table index is float4
|
||||
static const unsigned int ps_constant_offset_table[] = {
|
||||
0, 4, 8, 12, // C_COLORS, 16
|
||||
16, 20, 24, 28, // C_KCOLORS, 16
|
||||
32, // C_ALPHA, 4
|
||||
36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32
|
||||
68, 72, // C_ZBIAS, 8
|
||||
76, 80, // C_INDTEXSCALE, 8
|
||||
84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24
|
||||
108, 112, 116, // C_FOG, 12
|
||||
120, 124, 128, 132, 136, // C_PLIGHTS0, 20
|
||||
140, 144, 148, 152, 156, // C_PLIGHTS1, 20
|
||||
160, 164, 168, 172, 176, // C_PLIGHTS2, 20
|
||||
180, 184, 188, 192, 196, // C_PLIGHTS3, 20
|
||||
200, 204, 208, 212, 216, // C_PLIGHTS4, 20
|
||||
220, 224, 228, 232, 236, // C_PLIGHTS5, 20
|
||||
240, 244, 248, 252, 256, // C_PLIGHTS6, 20
|
||||
260, 264, 268, 272, 276, // C_PLIGHTS7, 20
|
||||
280, 284, 288, 292 // C_PMATERIALS, 16
|
||||
};
|
||||
void Renderer::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
psconstants[ps_constant_offset_table[const_number] ] = f1;
|
||||
psconstants[ps_constant_offset_table[const_number]+1] = f2;
|
||||
psconstants[ps_constant_offset_table[const_number]+2] = f3;
|
||||
psconstants[ps_constant_offset_table[const_number]+3] = f4;
|
||||
pscbufchanged = true;
|
||||
}
|
||||
|
||||
void Renderer::SetPSConstant4fv(unsigned int const_number, const float* f)
|
||||
{
|
||||
memcpy(&psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4);
|
||||
pscbufchanged = true;
|
||||
}
|
||||
|
||||
void Renderer::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
|
||||
{
|
||||
memcpy(&psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count);
|
||||
pscbufchanged = true;
|
||||
}
|
||||
|
||||
} // DX11
|
||||
59
Source/Core/VideoBackends/D3D/Src/PixelShaderCache.h
Normal file
59
Source/Core/VideoBackends/D3D/Src/PixelShaderCache.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PixelShaderGen.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
enum DSTALPHA_MODE;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class PixelShaderCache
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(DSTALPHA_MODE dstAlphaMode, u32 components); // TODO: Should be renamed to LoadShader
|
||||
static bool InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen);
|
||||
|
||||
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
|
||||
static ID3D11Buffer* &GetConstantBuffer();
|
||||
|
||||
static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled);
|
||||
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
|
||||
static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled);
|
||||
static ID3D11PixelShader* GetClearProgram();
|
||||
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
|
||||
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
|
||||
|
||||
static void InvalidateMSAAShaders();
|
||||
|
||||
private:
|
||||
struct PSCacheEntry
|
||||
{
|
||||
ID3D11PixelShader* shader;
|
||||
|
||||
std::string code;
|
||||
|
||||
PSCacheEntry() : shader(NULL) {}
|
||||
void Destroy() { SAFE_RELEASE(shader); }
|
||||
};
|
||||
|
||||
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
|
||||
|
||||
static PSCache PixelShaders;
|
||||
static const PSCacheEntry* last_entry;
|
||||
static PixelShaderUid last_uid;
|
||||
|
||||
static UidChecker<PixelShaderUid,PixelShaderCode> pixel_uid_checker;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
232
Source/Core/VideoBackends/D3D/Src/PointGeometryShader.cpp
Normal file
232
Source/Core/VideoBackends/D3D/Src/PointGeometryShader.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "PointGeometryShader.h"
|
||||
|
||||
#include <sstream>
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
struct PointGSParams
|
||||
{
|
||||
FLOAT PointSize; // In units of 1/6 of an EFB pixel
|
||||
FLOAT TexOffset;
|
||||
FLOAT VpWidth; // Width and height of viewport in EFB pixels
|
||||
FLOAT VpHeight;
|
||||
FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off)
|
||||
};
|
||||
|
||||
union PointGSParams_Padded
|
||||
{
|
||||
PointGSParams params;
|
||||
// Constant buffers must be a multiple of 16 bytes in size.
|
||||
u8 pad[(sizeof(PointGSParams) + 15) & ~15];
|
||||
};
|
||||
|
||||
static const char POINT_GS_COMMON[] =
|
||||
// The struct VS_OUTPUT used by the vertex shader goes here.
|
||||
"// dolphin-emu point geometry shader common part\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match PointGSParams above
|
||||
"{\n"
|
||||
"float PointSize;\n"
|
||||
"float TexOffset;\n"
|
||||
"float VpWidth;\n"
|
||||
"float VpHeight;\n"
|
||||
"float TexOffsetEnable[8];\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"[maxvertexcount(4)]\n"
|
||||
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
|
||||
"{\n"
|
||||
"VS_OUTPUT ptLL = input[0];\n"
|
||||
"VS_OUTPUT ptLR = ptLL;\n"
|
||||
"VS_OUTPUT ptUL = ptLL;\n"
|
||||
"VS_OUTPUT ptUR = ptLL;\n"
|
||||
|
||||
// Offset from center to upper right vertex
|
||||
// Lerp Params.PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1]
|
||||
"float2 offset = float2(Params.PointSize/Params.VpWidth, -Params.PointSize/Params.VpHeight) * input[0].pos.w;\n"
|
||||
|
||||
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
|
||||
"ptLR.pos.xy += float2(1,-1) * offset;\n"
|
||||
"ptUL.pos.xy += float2(-1,1) * offset;\n"
|
||||
"ptUR.pos.xy += offset;\n"
|
||||
|
||||
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
|
||||
|
||||
"#ifndef NUM_TEXCOORDS\n"
|
||||
"#error NUM_TEXCOORDS not defined\n"
|
||||
"#endif\n"
|
||||
|
||||
// Apply TexOffset to all tex coordinates in the vertex
|
||||
// FIXME: The game may be able to enable TexOffset for some coords and
|
||||
// disable for others, but where is that information stored?
|
||||
"#if NUM_TEXCOORDS >= 1\n"
|
||||
"ptLL.tex0.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[0];\n"
|
||||
"ptLR.tex0.xy += texOffset * Params.TexOffsetEnable[0];\n"
|
||||
"ptUR.tex0.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[0];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 2\n"
|
||||
"ptLL.tex1.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[1];\n"
|
||||
"ptLR.tex1.xy += texOffset * Params.TexOffsetEnable[1];\n"
|
||||
"ptUR.tex1.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[1];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 3\n"
|
||||
"ptLL.tex2.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[2];\n"
|
||||
"ptLR.tex2.xy += texOffset * Params.TexOffsetEnable[2];\n"
|
||||
"ptUR.tex2.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[2];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 4\n"
|
||||
"ptLL.tex3.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[3];\n"
|
||||
"ptLR.tex3.xy += texOffset * Params.TexOffsetEnable[3];\n"
|
||||
"ptUR.tex3.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[3];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 5\n"
|
||||
"ptLL.tex4.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[4];\n"
|
||||
"ptLR.tex4.xy += texOffset * Params.TexOffsetEnable[4];\n"
|
||||
"ptUR.tex4.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[4];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 6\n"
|
||||
"ptLL.tex5.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[5];\n"
|
||||
"ptLR.tex5.xy += texOffset * Params.TexOffsetEnable[5];\n"
|
||||
"ptUR.tex5.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[5];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 7\n"
|
||||
"ptLL.tex6.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[6];\n"
|
||||
"ptLR.tex6.xy += texOffset * Params.TexOffsetEnable[6];\n"
|
||||
"ptUR.tex6.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[6];\n"
|
||||
"#endif\n"
|
||||
"#if NUM_TEXCOORDS >= 8\n"
|
||||
"ptLL.tex7.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[7];\n"
|
||||
"ptLR.tex7.xy += texOffset * Params.TexOffsetEnable[7];\n"
|
||||
"ptUR.tex7.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[7];\n"
|
||||
"#endif\n"
|
||||
|
||||
"outStream.Append(ptLL);\n"
|
||||
"outStream.Append(ptLR);\n"
|
||||
"outStream.Append(ptUL);\n"
|
||||
"outStream.Append(ptUR);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
PointGeometryShader::PointGeometryShader()
|
||||
: m_ready(false), m_paramsBuffer(NULL)
|
||||
{ }
|
||||
|
||||
void PointGeometryShader::Init()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// Create constant buffer for uploading data to geometry shader
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams_Padded),
|
||||
D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
|
||||
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
|
||||
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
||||
void PointGeometryShader::Shutdown()
|
||||
{
|
||||
m_ready = false;
|
||||
|
||||
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
|
||||
{
|
||||
SAFE_RELEASE(it->second);
|
||||
}
|
||||
m_shaders.clear();
|
||||
|
||||
SAFE_RELEASE(m_paramsBuffer);
|
||||
}
|
||||
|
||||
bool PointGeometryShader::SetShader(u32 components, float pointSize,
|
||||
float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable)
|
||||
{
|
||||
if (!m_ready)
|
||||
return false;
|
||||
|
||||
// Make sure geometry shader for "components" is available
|
||||
ComboMap::iterator shaderIt = m_shaders.find(components);
|
||||
if (shaderIt == m_shaders.end())
|
||||
{
|
||||
// Generate new shader. Warning: not thread-safe.
|
||||
static char buffer[16384];
|
||||
ShaderCode code;
|
||||
code.SetBuffer(buffer);
|
||||
GenerateVSOutputStructForGS(code, components, API_D3D);
|
||||
code.Write("\n%s", POINT_GS_COMMON);
|
||||
|
||||
std::stringstream numTexCoordsStream;
|
||||
numTexCoordsStream << xfregs.numTexGen.numTexGens;
|
||||
|
||||
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
|
||||
components, xfregs.numTexGen.numTexGens);
|
||||
|
||||
const std::string& numTexCoordsStr = numTexCoordsStream.str();
|
||||
D3D_SHADER_MACRO macros[] = {
|
||||
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), macros);
|
||||
if (!newShader)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
|
||||
// Add dummy shader to prevent trying to compile again
|
||||
m_shaders[components] = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
|
||||
}
|
||||
|
||||
if (shaderIt != m_shaders.end())
|
||||
{
|
||||
if (shaderIt->second)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PointGSParams* params = (PointGSParams*)map.pData;
|
||||
params->PointSize = pointSize;
|
||||
|
||||
params->TexOffset = texOffset;
|
||||
params->VpWidth = vpWidth;
|
||||
params->VpHeight = vpHeight;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f;
|
||||
|
||||
D3D::context->Unmap(m_paramsBuffer, 0);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Failed to map point gs params buffer");
|
||||
|
||||
DEBUG_LOG(VIDEO, "Point params: size %f, texOffset %f, vpWidth %f, vpHeight %f",
|
||||
pointSize, texOffset, vpWidth, vpHeight);
|
||||
|
||||
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
|
||||
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
45
Source/Core/VideoBackends/D3D/Src/PointGeometryShader.h
Normal file
45
Source/Core/VideoBackends/D3D/Src/PointGeometryShader.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _POINTGEOMETRYSHADER_H
|
||||
#define _POINTGEOMETRYSHADER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11GeometryShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// This class manages a collection of point geometry shaders, one for each
|
||||
// vertex format.
|
||||
class PointGeometryShader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
PointGeometryShader();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
// Returns true on success, false on failure
|
||||
bool SetShader(u32 components, float pointSize, float texOffset,
|
||||
float vpWidth, float vpHeight, const bool* texOffsetEnable);
|
||||
|
||||
private:
|
||||
|
||||
bool m_ready;
|
||||
|
||||
ID3D11Buffer* m_paramsBuffer;
|
||||
|
||||
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
|
||||
|
||||
ComboMap m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1427
Source/Core/VideoBackends/D3D/Src/Render.cpp
Normal file
1427
Source/Core/VideoBackends/D3D/Src/Render.cpp
Normal file
File diff suppressed because it is too large
Load Diff
67
Source/Core/VideoBackends/D3D/Src/Render.h
Normal file
67
Source/Core/VideoBackends/D3D/Src/Render.h
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
#ifndef _RENDER_H_
|
||||
#define _RENDER_H_
|
||||
|
||||
#include "RenderBase.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
{
|
||||
public:
|
||||
Renderer();
|
||||
~Renderer();
|
||||
|
||||
void SetColorMask();
|
||||
void SetBlendMode(bool forceUpdate);
|
||||
void SetScissorRect(const TargetRectangle& rc);
|
||||
void SetGenerationMode();
|
||||
void SetDepthMode();
|
||||
void SetLogicOpMode();
|
||||
void SetDitherMode();
|
||||
void SetLineWidth();
|
||||
void SetSamplerState(int stage,int texindex);
|
||||
void SetInterlacingMode();
|
||||
|
||||
// TODO: Fix confusing names (see ResetAPIState and RestoreAPIState)
|
||||
void ApplyState(bool bUseDstAlpha);
|
||||
void RestoreState();
|
||||
|
||||
void ApplyCullDisable();
|
||||
void RestoreCull();
|
||||
|
||||
void RenderText(const char* pstr, int left, int top, u32 color);
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
|
||||
|
||||
void ResetAPIState();
|
||||
void RestoreAPIState();
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc);
|
||||
|
||||
void Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc,float Gamma);
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype);
|
||||
|
||||
void UpdateViewport(Matrix44& vpCorrection);
|
||||
|
||||
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
||||
|
||||
static bool CheckForResize();
|
||||
|
||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
||||
void SetPSConstant4fv(unsigned int const_number, const float *f);
|
||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
|
||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
||||
void SetVSConstant4fv(unsigned int const_number, const float *f);
|
||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
172
Source/Core/VideoBackends/D3D/Src/Television.cpp
Normal file
172
Source/Core/VideoBackends/D3D/Src/Television.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Television.h"
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "D3DUtil.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include <vector>
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
static const char YUYV_DECODER_PS[] =
|
||||
"// dolphin-emu YUYV decoder pixel shader\n"
|
||||
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"sampler Samp0 : register(s0);\n"
|
||||
|
||||
"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
|
||||
"1.164, 0.000, 1.596,\n"
|
||||
"1.164, -0.392, -0.813,\n"
|
||||
"1.164, 2.017, 0.000\n"
|
||||
");\n"
|
||||
|
||||
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
|
||||
|
||||
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
|
||||
// primaries, compressed to the range Y in 16..235, U and V in 16..240.
|
||||
// We want to convert it to RGB format with sRGB color primaries, with
|
||||
// range 0..255.
|
||||
|
||||
// Recover RGB components
|
||||
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
|
||||
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
|
||||
|
||||
// If we were really obsessed with accuracy, we would correct for the
|
||||
// differing color primaries between BT.601 and sRGB. However, this may not
|
||||
// be worth the trouble because:
|
||||
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
|
||||
// - sRGB's color primaries are actually an intermediate between BT.601's
|
||||
// NTSC and PAL primaries.
|
||||
// - If users even noticed any difference at all, they would be confused by
|
||||
// the slightly-different colors in the NTSC and PAL versions of the same
|
||||
// game.
|
||||
// - Even the game designers probably don't pay close attention to this
|
||||
// stuff.
|
||||
// Still, instructions on how to do it can be found at
|
||||
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
|
||||
|
||||
"ocol0 = float4(rgb_601, 1);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
Television::Television()
|
||||
: m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL)
|
||||
{ }
|
||||
|
||||
void Television::Init()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Create YUYV texture for real XFB mode
|
||||
|
||||
|
||||
// Initialize the texture with YCbCr black
|
||||
//
|
||||
// Some games use narrower XFB widths (Nintendo titles are fond of 608),
|
||||
// so the sampler's BorderColor won't cover the right side
|
||||
// (see sampler state below)
|
||||
const unsigned int MAX_XFB_SIZE = 2*(MAX_XFB_WIDTH) * MAX_XFB_HEIGHT;
|
||||
std::vector<u8> fill(MAX_XFB_SIZE);
|
||||
for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i)
|
||||
reinterpret_cast<u32*>(fill.data())[i] = 0x80108010;
|
||||
D3D11_SUBRESOURCE_DATA srd = { fill.data(), 2*(MAX_XFB_WIDTH), 0 };
|
||||
|
||||
// This texture format is designed for YUYV data.
|
||||
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
|
||||
DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture);
|
||||
CHECK(SUCCEEDED(hr), "create tv yuyv texture");
|
||||
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
|
||||
|
||||
// Create shader resource view for YUYV texture
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
|
||||
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
|
||||
DXGI_FORMAT_G8R8_G8B8_UNORM);
|
||||
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
|
||||
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
|
||||
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
|
||||
|
||||
// Create YUYV-decoding pixel shader
|
||||
|
||||
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS));
|
||||
CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader");
|
||||
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
|
||||
|
||||
// Create sampler state and set border color
|
||||
//
|
||||
// The default sampler border color of { 0.f, 0.f, 0.f, 0.f }
|
||||
// creates a green border around the image - see issue 6483
|
||||
// (remember, the XFB is being interpreted as YUYV, and 0,0,0,0
|
||||
// is actually two green pixels in YUYV - black should be 16,128,16,128,
|
||||
// but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering)
|
||||
float border[4] = { 128.0f/255.0f, 16.0f/255.0f, 128.0f/255.0f, 16.0f/255.0f };
|
||||
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
||||
D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER,
|
||||
0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
|
||||
hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState);
|
||||
CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state");
|
||||
D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state");
|
||||
}
|
||||
|
||||
void Television::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(m_pShader);
|
||||
SAFE_RELEASE(m_yuyvTextureSRV);
|
||||
SAFE_RELEASE(m_yuyvTexture);
|
||||
SAFE_RELEASE(m_samplerState);
|
||||
}
|
||||
|
||||
void Television::Submit(u32 xfbAddr, u32 width, u32 height)
|
||||
{
|
||||
m_curAddr = xfbAddr;
|
||||
m_curWidth = width;
|
||||
m_curHeight = height;
|
||||
|
||||
// Load data from GameCube RAM to YUYV texture
|
||||
u8* yuyvSrc = Memory::GetPointer(xfbAddr);
|
||||
D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1);
|
||||
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height);
|
||||
}
|
||||
|
||||
void Television::Render()
|
||||
{
|
||||
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
// Use real XFB mode
|
||||
// TODO: If this is the lower field, render at a vertical offset of 1
|
||||
// line down. We could even consider implementing a deinterlacing
|
||||
// algorithm.
|
||||
|
||||
MathUtil::Rectangle<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
|
||||
MathUtil::Rectangle<float> destRc(-1.f, 1.f, 1.f, -1.f);
|
||||
|
||||
D3D::context->PSSetSamplers(0, 1, &m_samplerState);
|
||||
|
||||
D3D::drawShadedTexSubQuad(
|
||||
m_yuyvTextureSRV, &sourceRc,
|
||||
MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
|
||||
&destRc,
|
||||
m_pShader,
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout());
|
||||
}
|
||||
else if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
// Use virtual XFB mode
|
||||
|
||||
// TODO: Eventually, Television should render the Virtual XFB mode
|
||||
// display as well.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
54
Source/Core/VideoBackends/D3D/Src/Television.h
Normal file
54
Source/Core/VideoBackends/D3D/Src/Television.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TELEVISION_H
|
||||
#define _TELEVISION_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11ShaderResourceView;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11SamplerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class Television
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Television();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Submit video data to be drawn. This will change the current state of the
|
||||
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
|
||||
// may be virtualized when rendering so the RAM may not actually be read.
|
||||
void Submit(u32 xfbAddr, u32 width, u32 height);
|
||||
|
||||
// Render the current state of the TV.
|
||||
void Render();
|
||||
|
||||
private:
|
||||
|
||||
// Properties of last Submit call
|
||||
u32 m_curAddr;
|
||||
u32 m_curWidth;
|
||||
u32 m_curHeight;
|
||||
|
||||
// Used for real XFB mode
|
||||
|
||||
ID3D11Texture2D* m_yuyvTexture;
|
||||
ID3D11ShaderResourceView* m_yuyvTextureSRV;
|
||||
ID3D11PixelShader* m_pShader;
|
||||
ID3D11SamplerState* m_samplerState;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
186
Source/Core/VideoBackends/D3D/Src/TextureCache.cpp
Normal file
186
Source/Core/VideoBackends/D3D/Src/TextureCache.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "RenderBase.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DUtil.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "TextureEncoder.h"
|
||||
#include "PSTextureEncoder.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
static TextureEncoder* g_encoder = NULL;
|
||||
const size_t MAX_COPY_BUFFERS = 25;
|
||||
ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 };
|
||||
|
||||
TextureCache::TCacheEntry::~TCacheEntry()
|
||||
{
|
||||
texture->Release();
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
{
|
||||
D3D::context->PSSetShaderResources(stage, 1, &texture->GetSRV());
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
{
|
||||
// TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs)
|
||||
static bool warn_once = true;
|
||||
if (level && warn_once)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!");
|
||||
warn_once = false;
|
||||
return false;
|
||||
}
|
||||
return SUCCEEDED(PD3DX11SaveTextureToFileA(D3D::context, texture->GetTex(), D3DX11_IFF_PNG, filename));
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level)
|
||||
{
|
||||
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
unsigned int height, unsigned int expanded_width,
|
||||
unsigned int tex_levels, PC_TexFormat pcfmt)
|
||||
{
|
||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
|
||||
D3D11_SUBRESOURCE_DATA srdata, *data = NULL;
|
||||
|
||||
if (tex_levels == 1)
|
||||
{
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
srdata.pSysMem = TextureCache::temp;
|
||||
srdata.SysMemPitch = 4 * expanded_width;
|
||||
|
||||
data = &srdata;
|
||||
}
|
||||
|
||||
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
|
||||
|
||||
ID3D11Texture2D *pTexture;
|
||||
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
||||
|
||||
TCacheEntry* const entry = new TCacheEntry(new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
|
||||
entry->usage = usage;
|
||||
|
||||
// TODO: better debug names
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
|
||||
|
||||
SAFE_RELEASE(pTexture);
|
||||
|
||||
if (tex_levels != 1)
|
||||
entry->Load(width, height, expanded_width, 0);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat)
|
||||
{
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// stretch picture with increased internal resolution
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtual_width, (float)virtual_height);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
// set transformation
|
||||
if (NULL == efbcopycbuf[cbufid])
|
||||
{
|
||||
const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
|
||||
D3D11_SUBRESOURCE_DATA data;
|
||||
data.pSysMem = colmat;
|
||||
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
|
||||
CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
|
||||
}
|
||||
D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]);
|
||||
|
||||
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
// TODO: try targetSource.asRECT();
|
||||
const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
|
||||
|
||||
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
|
||||
if (scaleByHalf)
|
||||
D3D::SetLinearCopySampler();
|
||||
else
|
||||
D3D::SetPointCopySampler();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL);
|
||||
|
||||
// Create texture copy
|
||||
D3D::drawShadedTexQuad(
|
||||
(srcFormat == PIXELFMT_Z24) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(),
|
||||
&sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
|
||||
(srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram(true) : PixelShaderCache::GetColorMatrixProgram(true),
|
||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
if (!g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
u8* dst = Memory::GetPointer(dstAddr);
|
||||
size_t encoded_size = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
|
||||
|
||||
u64 hash = GetHash64(dst, (int)encoded_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
|
||||
else if (!TextureCache::Find(addr, hash))
|
||||
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
|
||||
|
||||
this->hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
|
||||
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
|
||||
{
|
||||
return new TCacheEntry(D3DTexture2D::Create(scaled_tex_w, scaled_tex_h,
|
||||
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
|
||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM));
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
// FIXME: Is it safe here?
|
||||
g_encoder = new PSTextureEncoder;
|
||||
g_encoder->Init();
|
||||
}
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k)
|
||||
SAFE_RELEASE(efbcopycbuf[k]);
|
||||
|
||||
g_encoder->Shutdown();
|
||||
delete g_encoder;
|
||||
g_encoder = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
49
Source/Core/VideoBackends/D3D/Src/TextureCache.h
Normal file
49
Source/Core/VideoBackends/D3D/Src/TextureCache.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TextureCacheBase.h"
|
||||
|
||||
#include "D3DTexture.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class TextureCache : public ::TextureCache
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
~TextureCache();
|
||||
|
||||
private:
|
||||
struct TCacheEntry : TCacheEntryBase
|
||||
{
|
||||
D3DTexture2D *const texture;
|
||||
|
||||
D3D11_USAGE usage;
|
||||
|
||||
TCacheEntry(D3DTexture2D *_tex) : texture(_tex) {}
|
||||
~TCacheEntry();
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int levels);
|
||||
|
||||
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat);
|
||||
|
||||
void Bind(unsigned int stage);
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
};
|
||||
|
||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
|
||||
|
||||
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h);
|
||||
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;};
|
||||
};
|
||||
|
||||
}
|
||||
122
Source/Core/VideoBackends/D3D/Src/TextureEncoder.h
Normal file
122
Source/Core/VideoBackends/D3D/Src/TextureEncoder.h
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TEXTUREENCODER_H
|
||||
#define _TEXTUREENCODER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// 4-bit format: 8x8 texels / cache line
|
||||
// 8-bit format: 8x4 texels / cache line
|
||||
// 16-bit format: 4x4 texels / cache line
|
||||
// 32-bit format: 4x4 texels / 2 cache lines
|
||||
// Compressed format: 8x8 texels / cache line
|
||||
|
||||
// Document EFB encoding formats here with examples of where they are used.
|
||||
|
||||
// Format: 0 - R4
|
||||
// Used in The Legend of Zelda: The Wind Waker for character shadows (srcFormat 1,
|
||||
// isIntensity 1, scaleByHalf 1).
|
||||
|
||||
// Format: 1 - R8
|
||||
// FIXME: Unseen. May or may not be a duplicate of format 8.
|
||||
|
||||
// Format: 2 - A4 R4
|
||||
// FIXME: Unseen.
|
||||
|
||||
// Format: 3 - A8 R8
|
||||
// FIXME: Unseen.
|
||||
|
||||
// Format: 4 - R5 G6 B5
|
||||
// Used in Wind Waker for most render-to-texture effects like heat shimmer and
|
||||
// depth-of-field.
|
||||
|
||||
// Format: 5 - 1 R5 G5 B5 or 0 A3 R4 G4 B4
|
||||
// Used in Twilight Princess for character shadows.
|
||||
|
||||
// Format: 6 - A8 R8 A8 R8 | G8 B8 G8 B8
|
||||
// Used in Twilight Princess for bloom effect.
|
||||
|
||||
// Format: 7 - A8
|
||||
// Used in Metroid Prime 2 for the scan visor.
|
||||
|
||||
// Format: 8 - R8
|
||||
// Used in Twilight Princess for the map.
|
||||
|
||||
// Format: 9 - G8
|
||||
// FIXME: Unseen.
|
||||
|
||||
// Format: A - B8
|
||||
// Used in Metroid Prime 2 for the scan visor.
|
||||
|
||||
// Format: B - G8 R8
|
||||
// Used in Wind Waker for depth-of-field. Usually used with srcFormat 3 to
|
||||
// render depth textures. The bytes are swapped, so games have to correct it
|
||||
// in RAM before using it as a texture.
|
||||
|
||||
// Format: C - B8 G8
|
||||
// FIXME: Unseen.
|
||||
|
||||
const unsigned int BLOCK_WIDTHS[16] = {
|
||||
8, // R4
|
||||
8, // R8 (FIXME: duplicate of R8 below?)
|
||||
8, // A4 R4
|
||||
4, // A8 R8
|
||||
4, // R5 G6 B5
|
||||
4, // 1 R5 G5 B5 or 0 A3 R4 G4 B4
|
||||
4, // A8 R8 A8 R8 | G8 B8 G8 B8 (two cache lines)
|
||||
8, // A8
|
||||
8, // R8 (FIXME: duplicate of R8 above?)
|
||||
8, // G8
|
||||
8, // B8
|
||||
4, // G8 R8
|
||||
4, // B8 G8
|
||||
0, 0, 0 // Unknown formats
|
||||
};
|
||||
|
||||
const unsigned int BLOCK_HEIGHTS[16] = {
|
||||
8, // R4
|
||||
4, // R8 (FIXME: duplicate of R8 below?)
|
||||
4, // A4 R4
|
||||
4, // A8 R8
|
||||
4, // R5 G6 B5
|
||||
4, // 1 R5 G5 B5 or 0 A3 R4 G4 B4
|
||||
4, // A8 R8 A8 R8 | G8 B8 G8 B8 (two cache lines)
|
||||
4, // A8
|
||||
4, // R8 (FIXME: duplicate of R8 above?)
|
||||
4, // G8
|
||||
4, // B8
|
||||
4, // G8 R8
|
||||
4, // B8 G8
|
||||
0, 0, 0 // Unknown formats
|
||||
};
|
||||
|
||||
// Maximum number of bytes that can occur in a texture block-row generated by
|
||||
// the encoder
|
||||
static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH/4)*64;
|
||||
// The maximum amount of data that the texture encoder can generate in one call
|
||||
static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW*(EFB_HEIGHT/4);
|
||||
|
||||
class TextureEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
virtual ~TextureEncoder() { }
|
||||
|
||||
virtual void Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
// Returns size in bytes of encoded block of memory
|
||||
virtual size_t Encode(u8* dst, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect, bool isIntensity,
|
||||
bool scaleByHalf) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
272
Source/Core/VideoBackends/D3D/Src/VertexManager.cpp
Normal file
272
Source/Core/VideoBackends/D3D/Src/VertexManager.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
|
||||
#include "BPMemory.h"
|
||||
#include "Debugger.h"
|
||||
#include "IndexGenerator.h"
|
||||
#include "MainBase.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "RenderBase.h"
|
||||
#include "Render.h"
|
||||
#include "Statistics.h"
|
||||
#include "TextureCacheBase.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
// internal state for loading vertices
|
||||
extern NativeVertexFormat *g_nativeVertexFmt;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
// TODO: Find sensible values for these two
|
||||
const UINT IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
|
||||
const UINT VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
|
||||
const UINT MAX_VBUFFER_COUNT = 2;
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
{
|
||||
D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(IBUFFER_SIZE,
|
||||
D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
|
||||
m_vertex_draw_offset = 0;
|
||||
m_triangle_draw_index = 0;
|
||||
m_line_draw_index = 0;
|
||||
m_point_draw_index = 0;
|
||||
m_index_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
|
||||
m_vertex_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
|
||||
for (m_current_index_buffer = 0; m_current_index_buffer < MAX_VBUFFER_COUNT; m_current_index_buffer++)
|
||||
{
|
||||
m_index_buffers[m_current_index_buffer] = NULL;
|
||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_index_buffers[m_current_index_buffer])),
|
||||
"Failed to create index buffer.");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_index_buffers[m_current_index_buffer], "index buffer of VertexManager");
|
||||
}
|
||||
bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
bufdesc.ByteWidth = VBUFFER_SIZE;
|
||||
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
|
||||
{
|
||||
m_vertex_buffers[m_current_vertex_buffer] = NULL;
|
||||
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_vertex_buffers[m_current_vertex_buffer])),
|
||||
"Failed to create vertex buffer.");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vertex_buffers[m_current_vertex_buffer], "Vertex buffer of VertexManager");
|
||||
}
|
||||
m_current_vertex_buffer = 0;
|
||||
m_current_index_buffer = 0;
|
||||
m_index_buffer_cursor = IBUFFER_SIZE;
|
||||
m_vertex_buffer_cursor = VBUFFER_SIZE;
|
||||
m_lineShader.Init();
|
||||
m_pointShader.Init();
|
||||
}
|
||||
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
m_pointShader.Shutdown();
|
||||
m_lineShader.Shutdown();
|
||||
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
|
||||
{
|
||||
SAFE_RELEASE(m_vertex_buffers[m_current_vertex_buffer]);
|
||||
SAFE_RELEASE(m_index_buffers[m_current_vertex_buffer]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VertexManager::VertexManager()
|
||||
{
|
||||
CreateDeviceObjects();
|
||||
}
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void VertexManager::PrepareDrawBuffers()
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
||||
UINT vSize = UINT(s_pCurBufferPointer - s_pBaseBufferPointer);
|
||||
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||
if (m_vertex_buffer_cursor + vSize >= VBUFFER_SIZE)
|
||||
{
|
||||
// Wrap around
|
||||
m_current_vertex_buffer = (m_current_vertex_buffer + 1) % MAX_VBUFFER_COUNT;
|
||||
m_vertex_buffer_cursor = 0;
|
||||
MapType = D3D11_MAP_WRITE_DISCARD;
|
||||
}
|
||||
|
||||
D3D::context->Map(m_vertex_buffers[m_current_vertex_buffer], 0, MapType, 0, &map);
|
||||
|
||||
memcpy((u8*)map.pData + m_vertex_buffer_cursor, s_pBaseBufferPointer, vSize);
|
||||
D3D::context->Unmap(m_vertex_buffers[m_current_vertex_buffer], 0);
|
||||
m_vertex_draw_offset = m_vertex_buffer_cursor;
|
||||
m_vertex_buffer_cursor += vSize;
|
||||
|
||||
UINT iCount = IndexGenerator::GetTriangleindexLen() +
|
||||
IndexGenerator::GetLineindexLen() + IndexGenerator::GetPointindexLen();
|
||||
MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
|
||||
if (m_index_buffer_cursor + iCount >= (IBUFFER_SIZE / sizeof(u16)))
|
||||
{
|
||||
// Wrap around
|
||||
m_current_index_buffer = (m_current_index_buffer + 1) % MAX_VBUFFER_COUNT;
|
||||
m_index_buffer_cursor = 0;
|
||||
MapType = D3D11_MAP_WRITE_DISCARD;
|
||||
}
|
||||
D3D::context->Map(m_index_buffers[m_current_index_buffer], 0, MapType, 0, &map);
|
||||
|
||||
m_triangle_draw_index = m_index_buffer_cursor;
|
||||
m_line_draw_index = m_triangle_draw_index + IndexGenerator::GetTriangleindexLen();
|
||||
m_point_draw_index = m_line_draw_index + IndexGenerator::GetLineindexLen();
|
||||
memcpy((u16*)map.pData + m_triangle_draw_index, GetTriangleIndexBuffer(), sizeof(u16) * IndexGenerator::GetTriangleindexLen());
|
||||
memcpy((u16*)map.pData + m_line_draw_index, GetLineIndexBuffer(), sizeof(u16) * IndexGenerator::GetLineindexLen());
|
||||
memcpy((u16*)map.pData + m_point_draw_index, GetPointIndexBuffer(), sizeof(u16) * IndexGenerator::GetPointindexLen());
|
||||
D3D::context->Unmap(m_index_buffers[m_current_index_buffer], 0);
|
||||
m_index_buffer_cursor += iCount;
|
||||
|
||||
ADDSTAT(stats.thisFrame.bytesVertexStreamed, vSize);
|
||||
ADDSTAT(stats.thisFrame.bytesIndexStreamed, iCount*sizeof(u16));
|
||||
}
|
||||
|
||||
static const float LINE_PT_TEX_OFFSETS[8] = {
|
||||
0.f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.f, 1.f, 1.f
|
||||
};
|
||||
|
||||
void VertexManager::Draw(UINT stride)
|
||||
{
|
||||
D3D::context->IASetVertexBuffers(0, 1, &m_vertex_buffers[m_current_vertex_buffer], &stride, &m_vertex_draw_offset);
|
||||
D3D::context->IASetIndexBuffer(m_index_buffers[m_current_index_buffer], DXGI_FORMAT_R16_UINT, 0);
|
||||
|
||||
if (IndexGenerator::GetNumTriangles() > 0)
|
||||
{
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
D3D::context->DrawIndexed(IndexGenerator::GetTriangleindexLen(), m_triangle_draw_index, 0);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
// Disable culling for lines and points
|
||||
if (IndexGenerator::GetNumLines() > 0 || IndexGenerator::GetNumPoints() > 0)
|
||||
((DX11::Renderer*)g_renderer)->ApplyCullDisable();
|
||||
if (IndexGenerator::GetNumLines() > 0)
|
||||
{
|
||||
float lineWidth = float(bpmem.lineptwidth.linesize) / 6.f;
|
||||
float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
|
||||
float vpWidth = 2.0f * xfregs.viewport.wd;
|
||||
float vpHeight = -2.0f * xfregs.viewport.ht;
|
||||
|
||||
bool texOffsetEnable[8];
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
texOffsetEnable[i] = bpmem.texcoords[i].s.line_offset;
|
||||
|
||||
if (m_lineShader.SetShader(g_nativeVertexFmt->m_components, lineWidth,
|
||||
texOffset, vpWidth, vpHeight, texOffsetEnable))
|
||||
{
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
|
||||
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_line_draw_index, 0);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
|
||||
D3D::context->GSSetShader(NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
if (IndexGenerator::GetNumPoints() > 0)
|
||||
{
|
||||
float pointSize = float(bpmem.lineptwidth.pointsize) / 6.f;
|
||||
float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
|
||||
float vpWidth = 2.0f * xfregs.viewport.wd;
|
||||
float vpHeight = -2.0f * xfregs.viewport.ht;
|
||||
|
||||
bool texOffsetEnable[8];
|
||||
|
||||
for (int i = 0; i < 8; ++i)
|
||||
texOffsetEnable[i] = bpmem.texcoords[i].s.point_offset;
|
||||
|
||||
if (m_pointShader.SetShader(g_nativeVertexFmt->m_components, pointSize,
|
||||
texOffset, vpWidth, vpHeight, texOffsetEnable))
|
||||
{
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
|
||||
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_point_draw_index, 0);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
|
||||
D3D::context->GSSetShader(NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
if (IndexGenerator::GetNumLines() > 0 || IndexGenerator::GetNumPoints() > 0)
|
||||
((DX11::Renderer*)g_renderer)->RestoreCull();
|
||||
}
|
||||
|
||||
void VertexManager::vFlush()
|
||||
{
|
||||
u32 usedtextures = 0;
|
||||
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
|
||||
if (bpmem.tevorders[i / 2].getEnable(i & 1))
|
||||
usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1);
|
||||
|
||||
if (bpmem.genMode.numindstages > 0)
|
||||
for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1; ++i)
|
||||
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
|
||||
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++)
|
||||
{
|
||||
if (usedtextures & (1 << i))
|
||||
{
|
||||
g_renderer->SetSamplerState(i & 3, i >> 2);
|
||||
const FourTexUnits &tex = bpmem.tex[i >> 2];
|
||||
const TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i,
|
||||
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
|
||||
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
|
||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3),
|
||||
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
{
|
||||
// 0s are probably for no manual wrapping needed.
|
||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "error loading texture");
|
||||
}
|
||||
}
|
||||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
|
||||
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
|
||||
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||
|
||||
if (!PixelShaderCache::SetShader(
|
||||
useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE,
|
||||
g_nativeVertexFmt->m_components))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
|
||||
return;
|
||||
}
|
||||
if (!VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
|
||||
return;
|
||||
}
|
||||
PrepareDrawBuffers();
|
||||
unsigned int stride = g_nativeVertexFmt->GetVertexStride();
|
||||
g_nativeVertexFmt->SetupVertexPointers();
|
||||
g_renderer->ApplyState(useDstAlpha);
|
||||
|
||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
Draw(stride);
|
||||
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
|
||||
|
||||
g_renderer->RestoreState();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
50
Source/Core/VideoBackends/D3D/Src/VertexManager.h
Normal file
50
Source/Core/VideoBackends/D3D/Src/VertexManager.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VERTEXMANAGER_H
|
||||
#define _VERTEXMANAGER_H
|
||||
|
||||
#include "VertexManagerBase.h"
|
||||
#include "LineGeometryShader.h"
|
||||
#include "PointGeometryShader.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class VertexManager : public ::VertexManager
|
||||
{
|
||||
public:
|
||||
VertexManager();
|
||||
~VertexManager();
|
||||
|
||||
NativeVertexFormat* CreateNativeVertexFormat();
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
private:
|
||||
|
||||
void PrepareDrawBuffers();
|
||||
void Draw(u32 stride);
|
||||
// temp
|
||||
void vFlush();
|
||||
|
||||
u32 m_vertex_buffer_cursor;
|
||||
u32 m_vertex_draw_offset;
|
||||
u32 m_index_buffer_cursor;
|
||||
u32 m_current_vertex_buffer;
|
||||
u32 m_current_index_buffer;
|
||||
u32 m_triangle_draw_index;
|
||||
u32 m_line_draw_index;
|
||||
u32 m_point_draw_index;
|
||||
typedef ID3D11Buffer* PID3D11Buffer;
|
||||
PID3D11Buffer* m_index_buffers;
|
||||
PID3D11Buffer* m_vertex_buffers;
|
||||
|
||||
LineGeometryShader m_lineShader;
|
||||
PointGeometryShader m_pointShader;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
315
Source/Core/VideoBackends/D3D/Src/VertexShaderCache.cpp
Normal file
315
Source/Core/VideoBackends/D3D/Src/VertexShaderCache.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "FileUtil.h"
|
||||
#include "LinearDiskCache.h"
|
||||
|
||||
#include "Debugger.h"
|
||||
#include "Statistics.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "D3DShader.h"
|
||||
#include "Globals.h"
|
||||
#include "VertexShaderCache.h"
|
||||
|
||||
#include "ConfigManager.h"
|
||||
|
||||
// See comment near the bottom of this file
|
||||
static unsigned int vs_constant_offset_table[C_VENVCONST_END];
|
||||
float vsconstants[C_VENVCONST_END*4];
|
||||
bool vscbufchanged = true;
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
|
||||
VertexShaderUid VertexShaderCache::last_uid;
|
||||
UidChecker<VertexShaderUid,VertexShaderCode> VertexShaderCache::vertex_uid_checker;
|
||||
|
||||
static ID3D11VertexShader* SimpleVertexShader = NULL;
|
||||
static ID3D11VertexShader* ClearVertexShader = NULL;
|
||||
static ID3D11InputLayout* SimpleLayout = NULL;
|
||||
static ID3D11InputLayout* ClearLayout = NULL;
|
||||
|
||||
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
|
||||
|
||||
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
|
||||
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
|
||||
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; }
|
||||
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; }
|
||||
|
||||
ID3D11Buffer* vscbuf = NULL;
|
||||
|
||||
ID3D11Buffer* &VertexShaderCache::GetConstantBuffer()
|
||||
{
|
||||
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
|
||||
if (vscbufchanged)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, vsconstants, sizeof(vsconstants));
|
||||
D3D::context->Unmap(vscbuf, 0);
|
||||
vscbufchanged = false;
|
||||
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(vsconstants));
|
||||
}
|
||||
return vscbuf;
|
||||
}
|
||||
|
||||
// this class will load the precompiled shaders into our cache
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader<VertexShaderUid, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const VertexShaderUid &key, const u8 *value, u32 value_size)
|
||||
{
|
||||
D3DBlob* blob = new D3DBlob(value_size, value);
|
||||
VertexShaderCache::InsertByteCode(key, blob);
|
||||
blob->Release();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const char simple_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
"float4 vPosition : POSITION;\n"
|
||||
"float2 vTexCoord : TEXCOORD0;\n"
|
||||
"float vTexCoord1 : TEXCOORD1;\n"
|
||||
"};\n"
|
||||
"VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
"VSOUTPUT OUT;\n"
|
||||
"OUT.vPosition = inPosition;\n"
|
||||
"OUT.vTexCoord = inTEX0.xy;\n"
|
||||
"OUT.vTexCoord1 = inTEX0.z;\n"
|
||||
"return OUT;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
const char clear_shader_code[] = {
|
||||
"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
"float4 vPosition : POSITION;\n"
|
||||
"float4 vColor0 : COLOR0;\n"
|
||||
"};\n"
|
||||
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
|
||||
"{\n"
|
||||
"VSOUTPUT OUT;\n"
|
||||
"OUT.vPosition = inPosition;\n"
|
||||
"OUT.vColor0 = inColor0;\n"
|
||||
"return OUT;\n"
|
||||
"}\n"
|
||||
};
|
||||
|
||||
void VertexShaderCache::Init()
|
||||
{
|
||||
const D3D11_INPUT_ELEMENT_DESC simpleelems[2] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
|
||||
};
|
||||
const D3D11_INPUT_ELEMENT_DESC clearelems[2] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
|
||||
unsigned int cbsize = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16
|
||||
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
|
||||
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, NULL, &vscbuf);
|
||||
CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", cbsize);
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "vertex shader constant buffer used to emulate the GX pipeline");
|
||||
|
||||
D3DBlob* blob;
|
||||
D3D::CompileVertexShader(simple_shader_code, sizeof(simple_shader_code), &blob);
|
||||
D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout);
|
||||
SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
||||
if (SimpleLayout == NULL || SimpleVertexShader == NULL) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
|
||||
blob->Release();
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout");
|
||||
|
||||
D3D::CompileVertexShader(clear_shader_code, sizeof(clear_shader_code), &blob);
|
||||
D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout);
|
||||
ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
|
||||
if (ClearLayout == NULL || ClearVertexShader == NULL) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
|
||||
blob->Release();
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout");
|
||||
|
||||
Clear();
|
||||
|
||||
// these values are hardcoded, they depend on internal D3DCompile behavior
|
||||
// TODO: Do this with D3DReflect or something instead
|
||||
unsigned int k;
|
||||
for (k = 0;k < 6;k++) vs_constant_offset_table[C_POSNORMALMATRIX+k] = 0+4*k;
|
||||
for (k = 0;k < 4;k++) vs_constant_offset_table[C_PROJECTION+k] = 24+4*k;
|
||||
for (k = 0;k < 4;k++) vs_constant_offset_table[C_MATERIALS+k] = 40+4*k;
|
||||
for (k = 0;k < 40;k++) vs_constant_offset_table[C_LIGHTS+k] = 56+4*k;
|
||||
for (k = 0;k < 24;k++) vs_constant_offset_table[C_TEXMATRICES+k] = 216+4*k;
|
||||
for (k = 0;k < 64;k++) vs_constant_offset_table[C_TRANSFORMMATRICES+k] = 312+4*k;
|
||||
for (k = 0;k < 32;k++) vs_constant_offset_table[C_NORMALMATRICES+k] = 568+4*k;
|
||||
for (k = 0;k < 64;k++) vs_constant_offset_table[C_POSTTRANSFORMMATRICES+k] = 696+4*k;
|
||||
vs_constant_offset_table[C_DEPTHPARAMS] = 952;
|
||||
|
||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
|
||||
|
||||
SETSTAT(stats.numVertexShadersCreated, 0);
|
||||
SETSTAT(stats.numVertexShadersAlive, 0);
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
VertexShaderCacheInserter inserter;
|
||||
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
|
||||
if (g_Config.bEnableShaderDebugging)
|
||||
Clear();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
void VertexShaderCache::Clear()
|
||||
{
|
||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
vshaders.clear();
|
||||
vertex_uid_checker.Invalidate();
|
||||
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(vscbuf);
|
||||
|
||||
SAFE_RELEASE(SimpleVertexShader);
|
||||
SAFE_RELEASE(ClearVertexShader);
|
||||
|
||||
SAFE_RELEASE(SimpleLayout);
|
||||
SAFE_RELEASE(ClearLayout);
|
||||
|
||||
Clear();
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool VertexShaderCache::SetShader(u32 components)
|
||||
{
|
||||
VertexShaderUid uid;
|
||||
GetVertexShaderUid(uid, components, API_D3D);
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
VertexShaderCode code;
|
||||
GenerateVertexShaderCode(code, components, API_D3D);
|
||||
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
|
||||
}
|
||||
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return (last_entry->shader != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
VSCache::iterator iter = vshaders.find(uid);
|
||||
if (iter != vshaders.end())
|
||||
{
|
||||
const VSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return (entry.shader != NULL);
|
||||
}
|
||||
|
||||
VertexShaderCode code;
|
||||
GenerateVertexShaderCode(code, components, API_D3D);
|
||||
|
||||
D3DBlob* pbytecode = NULL;
|
||||
D3D::CompileVertexShader(code.GetBuffer(), (int)strlen(code.GetBuffer()), &pbytecode);
|
||||
|
||||
if (pbytecode == NULL)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return false;
|
||||
}
|
||||
g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
|
||||
|
||||
bool success = InsertByteCode(uid, pbytecode);
|
||||
pbytecode->Release();
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging && success)
|
||||
{
|
||||
vshaders[uid].code = code.GetBuffer();
|
||||
}
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob)
|
||||
{
|
||||
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
|
||||
if (shader == NULL)
|
||||
return false;
|
||||
|
||||
// TODO: Somehow make the debug name a bit more specific
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry entry;
|
||||
entry.shader = shader;
|
||||
entry.SetByteCode(bcodeblob);
|
||||
|
||||
vshaders[uid] = entry;
|
||||
last_entry = &vshaders[uid];
|
||||
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// These are "callbacks" from VideoCommon and thus must be outside namespace DX11.
|
||||
// This will have to be changed when we merge.
|
||||
|
||||
// maps the constant numbers to float indices in the constant buffer
|
||||
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
vsconstants[vs_constant_offset_table[const_number] ] = f1;
|
||||
vsconstants[vs_constant_offset_table[const_number]+1] = f2;
|
||||
vsconstants[vs_constant_offset_table[const_number]+2] = f3;
|
||||
vsconstants[vs_constant_offset_table[const_number]+3] = f4;
|
||||
vscbufchanged = true;
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4fv(unsigned int const_number, const float* f)
|
||||
{
|
||||
memcpy(&vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4);
|
||||
vscbufchanged = true;
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f)
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
memcpy(&vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3);
|
||||
vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f;
|
||||
}
|
||||
vscbufchanged = true;
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
|
||||
{
|
||||
memcpy(&vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count);
|
||||
vscbufchanged = true;
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
68
Source/Core/VideoBackends/D3D/Src/VertexShaderCache.h
Normal file
68
Source/Core/VideoBackends/D3D/Src/VertexShaderCache.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VERTEXSHADERCACHE_H
|
||||
#define _VERTEXSHADERCACHE_H
|
||||
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DBlob.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
class VertexShaderCache
|
||||
{
|
||||
public:
|
||||
static void Init();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(u32 components); // TODO: Should be renamed to LoadShader
|
||||
|
||||
static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; }
|
||||
static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; }
|
||||
static ID3D11Buffer* &GetConstantBuffer();
|
||||
|
||||
static ID3D11VertexShader* GetSimpleVertexShader();
|
||||
static ID3D11VertexShader* GetClearVertexShader();
|
||||
static ID3D11InputLayout* GetSimpleInputLayout();
|
||||
static ID3D11InputLayout* GetClearInputLayout();
|
||||
|
||||
static bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob);
|
||||
|
||||
private:
|
||||
struct VSCacheEntry
|
||||
{
|
||||
ID3D11VertexShader* shader;
|
||||
D3DBlob* bytecode; // needed to initialize the input layout
|
||||
|
||||
std::string code;
|
||||
|
||||
VSCacheEntry() : shader(NULL), bytecode(NULL) {}
|
||||
void SetByteCode(D3DBlob* blob)
|
||||
{
|
||||
SAFE_RELEASE(bytecode);
|
||||
bytecode = blob;
|
||||
blob->AddRef();
|
||||
}
|
||||
void Destroy()
|
||||
{
|
||||
SAFE_RELEASE(shader);
|
||||
SAFE_RELEASE(bytecode);
|
||||
}
|
||||
};
|
||||
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
|
||||
|
||||
static VSCache vshaders;
|
||||
static const VSCacheEntry* last_entry;
|
||||
static VertexShaderUid last_uid;
|
||||
|
||||
static UidChecker<VertexShaderUid,VertexShaderCode> vertex_uid_checker;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
#endif // _VERTEXSHADERCACHE_H
|
||||
29
Source/Core/VideoBackends/D3D/Src/VideoBackend.h
Normal file
29
Source/Core/VideoBackends/D3D/Src/VideoBackend.h
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef DX11_VIDEO_BACKEND_H_
|
||||
#define DX11_VIDEO_BACKEND_H_
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class VideoBackend : public VideoBackendHardware
|
||||
{
|
||||
bool Initialize(void *&);
|
||||
void Shutdown();
|
||||
|
||||
std::string GetName();
|
||||
std::string GetDisplayName();
|
||||
|
||||
void Video_Prepare();
|
||||
void Video_Cleanup();
|
||||
|
||||
void ShowConfig(void* parent);
|
||||
|
||||
void UpdateFPSDisplay(const char*);
|
||||
unsigned int PeekMessages();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
374
Source/Core/VideoBackends/D3D/Src/XFBEncoder.cpp
Normal file
374
Source/Core/VideoBackends/D3D/Src/XFBEncoder.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "XFBEncoder.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DBlob.h"
|
||||
#include "D3DShader.h"
|
||||
#include "Render.h"
|
||||
#include "GfxState.h"
|
||||
#include "FramebufferManager.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union XFBEncodeParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT Width; // Width and height of encoded XFB in luma pixels
|
||||
FLOAT Height;
|
||||
FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
|
||||
FLOAT TexTop;
|
||||
FLOAT TexRight;
|
||||
FLOAT TexBottom;
|
||||
FLOAT Gamma;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size
|
||||
u8 pad[32]; // Pad to the next multiple of 16
|
||||
};
|
||||
|
||||
static const char XFB_ENCODE_VS[] =
|
||||
"// dolphin-emu XFB encoder vertex shader\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match XFBEncodeParams above
|
||||
"{\n"
|
||||
"float Width;\n"
|
||||
"float Height;\n"
|
||||
"float TexLeft;\n"
|
||||
"float TexTop;\n"
|
||||
"float TexRight;\n"
|
||||
"float TexBottom;\n"
|
||||
"float Gamma;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"struct Output\n"
|
||||
"{\n"
|
||||
"float4 Pos : SV_Position;\n"
|
||||
"float2 Coord : ENCODECOORD;\n"
|
||||
"};\n"
|
||||
|
||||
"Output main(in float2 Pos : POSITION)\n"
|
||||
"{\n"
|
||||
"Output result;\n"
|
||||
"result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n"
|
||||
"result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n"
|
||||
"return result;\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
static const char XFB_ENCODE_PS[] =
|
||||
"// dolphin-emu XFB encoder pixel shader\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match XFBEncodeParams above
|
||||
"{\n"
|
||||
"float Width;\n"
|
||||
"float Height;\n"
|
||||
"float TexLeft;\n"
|
||||
"float TexTop;\n"
|
||||
"float TexRight;\n"
|
||||
"float TexBottom;\n"
|
||||
"float Gamma;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"Texture2D EFBTexture : register(t0);\n"
|
||||
"sampler EFBSampler : register(s0);\n"
|
||||
|
||||
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
|
||||
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
|
||||
"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
|
||||
"0.257, 0.504, 0.098, 16.0/255.0,\n"
|
||||
"-0.148, -0.291, 0.439, 128.0/255.0,\n"
|
||||
"0.439, -0.368, -0.071, 128.0/255.0\n"
|
||||
");\n"
|
||||
|
||||
"float3 SampleEFB(float2 coord)\n"
|
||||
"{\n"
|
||||
"float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n"
|
||||
"return EFBTexture.Sample(EFBSampler, texCoord).rgb;\n"
|
||||
"}\n"
|
||||
|
||||
"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
|
||||
"{\n"
|
||||
"float2 baseCoord = Coord * float2(2,1);\n"
|
||||
// FIXME: Shall we apply gamma here, or apply it below to the Y components?
|
||||
// Be careful if you apply it to Y! The Y components are in the range (16..235) / 255.
|
||||
"float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
|
||||
"float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
|
||||
"float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
|
||||
|
||||
"float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
|
||||
"float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n"
|
||||
"float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n"
|
||||
|
||||
// The Y components correspond to two EFB pixels, while the U and V are
|
||||
// made from a blend of three EFB pixels.
|
||||
"float y0 = yuvM.r;\n"
|
||||
"float y1 = yuvR.r;\n"
|
||||
"float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n"
|
||||
"float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n"
|
||||
|
||||
"ocol0 = float4(y0, u0, y1, v0);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
|
||||
};
|
||||
|
||||
static const struct QuadVertex
|
||||
{
|
||||
float posX;
|
||||
float posY;
|
||||
} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
|
||||
|
||||
XFBEncoder::XFBEncoder()
|
||||
: m_out(NULL), m_outRTV(NULL), m_outStage(NULL), m_encodeParams(NULL),
|
||||
m_quad(NULL), m_vShader(NULL), m_quadLayout(NULL), m_pShader(NULL),
|
||||
m_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL),
|
||||
m_xfbEncodeRastState(NULL), m_efbSampler(NULL)
|
||||
{ }
|
||||
|
||||
void XFBEncoder::Init()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Create output texture
|
||||
|
||||
// The pixel shader can generate one YUYV entry per pixel. One YUYV entry
|
||||
// is created for every two EFB pixels.
|
||||
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
|
||||
D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
|
||||
D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
|
||||
|
||||
// Create output render target view
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
|
||||
D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
|
||||
D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
|
||||
|
||||
// Create output staging buffer
|
||||
|
||||
t2dd.Usage = D3D11_USAGE_STAGING;
|
||||
t2dd.BindFlags = 0;
|
||||
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
|
||||
D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
|
||||
|
||||
// Create constant buffer for uploading params to shaders
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
|
||||
D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
|
||||
|
||||
// Create vertex quad
|
||||
|
||||
bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
|
||||
D3D11_USAGE_IMMUTABLE);
|
||||
D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
|
||||
|
||||
hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
|
||||
D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
|
||||
|
||||
// Create vertex shader
|
||||
|
||||
D3DBlob* bytecode = NULL;
|
||||
if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
|
||||
D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
|
||||
|
||||
// Create input layout for vertex quad using bytecode from vertex shader
|
||||
|
||||
hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
|
||||
sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
|
||||
bytecode->Data(), bytecode->Size(), &m_quadLayout);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
|
||||
D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
|
||||
|
||||
bytecode->Release();
|
||||
|
||||
// Create pixel shader
|
||||
|
||||
m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS));
|
||||
if (!m_pShader)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
|
||||
return;
|
||||
}
|
||||
D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
|
||||
|
||||
// Create blend state
|
||||
|
||||
D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
|
||||
hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode blend state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
|
||||
|
||||
// Create depth state
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
|
||||
dsd.DepthEnable = FALSE;
|
||||
hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode depth state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
|
||||
|
||||
// Create rasterizer state
|
||||
|
||||
D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
|
||||
rd.CullMode = D3D11_CULL_NONE;
|
||||
rd.DepthClipEnable = FALSE;
|
||||
hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
|
||||
|
||||
// Create EFB texture sampler
|
||||
|
||||
D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
|
||||
// FIXME: Should we really use point sampling here?
|
||||
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
|
||||
D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
|
||||
}
|
||||
|
||||
void XFBEncoder::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(m_efbSampler);
|
||||
SAFE_RELEASE(m_xfbEncodeRastState);
|
||||
SAFE_RELEASE(m_xfbEncodeDepthState);
|
||||
SAFE_RELEASE(m_xfbEncodeBlendState);
|
||||
SAFE_RELEASE(m_pShader);
|
||||
SAFE_RELEASE(m_quadLayout);
|
||||
SAFE_RELEASE(m_vShader);
|
||||
SAFE_RELEASE(m_quad);
|
||||
SAFE_RELEASE(m_encodeParams);
|
||||
SAFE_RELEASE(m_outStage);
|
||||
SAFE_RELEASE(m_outRTV);
|
||||
SAFE_RELEASE(m_out);
|
||||
}
|
||||
|
||||
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Reset API
|
||||
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// Set up all the state for XFB encoding
|
||||
|
||||
D3D::context->PSSetShader(m_pShader, NULL, 0);
|
||||
D3D::context->VSSetShader(m_vShader, NULL, 0);
|
||||
|
||||
D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
|
||||
D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
|
||||
D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
D3D::context->IASetInputLayout(m_quadLayout);
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
UINT stride = sizeof(QuadVertex);
|
||||
UINT offset = 0;
|
||||
D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset);
|
||||
|
||||
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
|
||||
XFBEncodeParams params = { 0 };
|
||||
params.Width = FLOAT(width);
|
||||
params.Height = FLOAT(height);
|
||||
params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth();
|
||||
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight();
|
||||
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth();
|
||||
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight();
|
||||
params.Gamma = gamma;
|
||||
D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, ¶ms, 0, 0);
|
||||
|
||||
D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams);
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL);
|
||||
|
||||
ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV();
|
||||
|
||||
D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams);
|
||||
D3D::context->PSSetShaderResources(0, 1, &pEFB);
|
||||
D3D::context->PSSetSamplers(0, 1, &m_efbSampler);
|
||||
|
||||
// Encode!
|
||||
|
||||
D3D::context->Draw(4, 0);
|
||||
|
||||
// Copy to staging buffer
|
||||
|
||||
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1);
|
||||
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
|
||||
|
||||
// Clean up state
|
||||
|
||||
IUnknown* nullDummy = NULL;
|
||||
|
||||
D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy);
|
||||
D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy);
|
||||
D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
|
||||
|
||||
D3D::context->OMSetRenderTargets(0, NULL, NULL);
|
||||
|
||||
D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
|
||||
|
||||
D3D::stateman->PopRasterizerState();
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopBlendState();
|
||||
|
||||
D3D::context->PSSetShader(NULL, NULL, 0);
|
||||
D3D::context->VSSetShader(NULL, NULL, 0);
|
||||
|
||||
// Transfer staging buffer to GameCube/Wii RAM
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map = { 0 };
|
||||
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
|
||||
CHECK(SUCCEEDED(hr), "map staging buffer");
|
||||
|
||||
u8* src = (u8*)map.pData;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
memcpy(dst, src, 2*width);
|
||||
dst += bpmem.copyMipMapStrideChannels*32;
|
||||
src += map.RowPitch;
|
||||
}
|
||||
|
||||
D3D::context->Unmap(m_outStage, 0);
|
||||
|
||||
// Restore API
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
D3D::context->OMSetRenderTargets(1,
|
||||
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
|
||||
FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
||||
}
|
||||
|
||||
}
|
||||
55
Source/Core/VideoBackends/D3D/Src/XFBEncoder.h
Normal file
55
Source/Core/VideoBackends/D3D/Src/XFBEncoder.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _XFBENCODER_H
|
||||
#define _XFBENCODER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11RenderTargetView;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11InputLayout;
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
struct ID3D11SamplerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class XFBEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XFBEncoder();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Texture2D* m_out;
|
||||
ID3D11RenderTargetView* m_outRTV;
|
||||
ID3D11Texture2D* m_outStage;
|
||||
ID3D11Buffer* m_encodeParams;
|
||||
ID3D11Buffer* m_quad;
|
||||
ID3D11VertexShader* m_vShader;
|
||||
ID3D11InputLayout* m_quadLayout;
|
||||
ID3D11PixelShader* m_pShader;
|
||||
ID3D11BlendState* m_xfbEncodeBlendState;
|
||||
ID3D11DepthStencilState* m_xfbEncodeDepthState;
|
||||
ID3D11RasterizerState* m_xfbEncodeRastState;
|
||||
ID3D11SamplerState* m_efbSampler;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
245
Source/Core/VideoBackends/D3D/Src/main.cpp
Normal file
245
Source/Core/VideoBackends/D3D/Src/main.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
#include "BPStructs.h"
|
||||
#include "CommandProcessor.h"
|
||||
#include "Fifo.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "VertexLoaderManager.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "Core.h"
|
||||
#include "Host.h"
|
||||
|
||||
#include "Debugger/DebuggerPanel.h"
|
||||
#include "DLCache.h"
|
||||
#include "EmuWindow.h"
|
||||
#include "IndexGenerator.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Globals.h"
|
||||
#include "IniFile.h"
|
||||
#include "VideoConfigDiag.h"
|
||||
|
||||
#include "D3DUtil.h"
|
||||
#include "D3DBase.h"
|
||||
#include "PerfQuery.h"
|
||||
#include "PixelShaderCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexShaderCache.h"
|
||||
|
||||
#include "VideoBackend.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
unsigned int VideoBackend::PeekMessages()
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void VideoBackend::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
TCHAR temp[512];
|
||||
swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs | D3D | %hs"), scm_rev_str, text);
|
||||
EmuWindow::SetWindowText(temp);
|
||||
}
|
||||
|
||||
std::string VideoBackend::GetName()
|
||||
{
|
||||
return "D3D";
|
||||
}
|
||||
|
||||
std::string VideoBackend::GetDisplayName()
|
||||
{
|
||||
return "Direct3D";
|
||||
}
|
||||
|
||||
void InitBackendInfo()
|
||||
{
|
||||
HRESULT hr = DX11::D3D::LoadDXGI();
|
||||
if (SUCCEEDED(hr)) hr = DX11::D3D::LoadD3D();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DX11::D3D::UnloadDXGI();
|
||||
return;
|
||||
}
|
||||
|
||||
g_Config.backend_info.APIType = API_D3D;
|
||||
g_Config.backend_info.bUseRGBATextures = true; // the GX formats barely match any D3D11 formats
|
||||
g_Config.backend_info.bUseMinimalMipCount = true;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
g_Config.backend_info.bSupportsFormatReinterpretation = true;
|
||||
g_Config.backend_info.bSupportsPixelLighting = true;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = true;
|
||||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* ad;
|
||||
hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
if (FAILED(hr))
|
||||
PanicAlert("Failed to create IDXGIFactory object");
|
||||
|
||||
// adapters
|
||||
g_Config.backend_info.Adapters.clear();
|
||||
g_Config.backend_info.AAModes.clear();
|
||||
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
const size_t adapter_index = g_Config.backend_info.Adapters.size();
|
||||
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
ad->GetDesc(&desc);
|
||||
|
||||
// TODO: These don't get updated on adapter change, yet
|
||||
if (adapter_index == g_Config.iAdapter)
|
||||
{
|
||||
char buf[32];
|
||||
std::vector<DXGI_SAMPLE_DESC> modes;
|
||||
modes = DX11::D3D::EnumAAModes(ad);
|
||||
for (unsigned int i = 0; i < modes.size(); ++i)
|
||||
{
|
||||
if (i == 0) sprintf_s(buf, 32, _trans("None"));
|
||||
else if (modes[i].Quality) sprintf_s(buf, 32, _trans("%d samples (quality level %d)"), modes[i].Count, modes[i].Quality);
|
||||
else sprintf_s(buf, 32, _trans("%d samples"), modes[i].Count);
|
||||
g_Config.backend_info.AAModes.push_back(buf);
|
||||
}
|
||||
|
||||
// Requires the earlydepthstencil attribute (only available in shader model 5)
|
||||
g_Config.backend_info.bSupportsEarlyZ = (DX11::D3D::GetFeatureLevel(ad) == D3D_FEATURE_LEVEL_11_0);
|
||||
}
|
||||
|
||||
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
|
||||
ad->Release();
|
||||
}
|
||||
|
||||
factory->Release();
|
||||
|
||||
// Clear ppshaders string vector
|
||||
g_Config.backend_info.PPShaders.clear();
|
||||
|
||||
DX11::D3D::UnloadDXGI();
|
||||
DX11::D3D::UnloadD3D();
|
||||
}
|
||||
|
||||
void VideoBackend::ShowConfig(void *_hParent)
|
||||
{
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
InitBackendInfo();
|
||||
VideoConfigDiag diag((wxWindow*)_hParent, _trans("Direct3D"), "gfx_dx11");
|
||||
diag.ShowModal();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void *&window_handle)
|
||||
{
|
||||
InitializeShared();
|
||||
InitBackendInfo();
|
||||
|
||||
frameCount = 0;
|
||||
|
||||
const SCoreStartupParameter& core_params = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
|
||||
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini").c_str());
|
||||
g_Config.GameIniLoad();
|
||||
g_Config.UpdateProjectionHack();
|
||||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
||||
window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Loading - Please wait."));
|
||||
if (window_handle == NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "An error has occurred while trying to create the window.");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_BackendInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoBackend::Video_Prepare()
|
||||
{
|
||||
// Better be safe...
|
||||
s_efbAccessRequested = FALSE;
|
||||
s_FifoShuttingDown = FALSE;
|
||||
s_swapRequested = FALSE;
|
||||
|
||||
// internal interfaces
|
||||
g_renderer = new Renderer;
|
||||
g_texture_cache = new TextureCache;
|
||||
g_vertex_manager = new VertexManager;
|
||||
g_perf_query = new PerfQuery;
|
||||
VertexShaderCache::Init();
|
||||
PixelShaderCache::Init();
|
||||
D3D::InitUtils();
|
||||
|
||||
// VideoCommon
|
||||
BPInit();
|
||||
Fifo_Init();
|
||||
IndexGenerator::Init();
|
||||
VertexLoaderManager::Init();
|
||||
OpcodeDecoder_Init();
|
||||
VertexShaderManager::Init();
|
||||
PixelShaderManager::Init();
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
DLCache::Init();
|
||||
|
||||
// Tell the host that the window is ready
|
||||
Host_Message(WM_USER_CREATE);
|
||||
}
|
||||
|
||||
void VideoBackend::Shutdown()
|
||||
{
|
||||
s_BackendInitialized = false;
|
||||
|
||||
// TODO: should be in Video_Cleanup
|
||||
if (g_renderer)
|
||||
{
|
||||
s_efbAccessRequested = FALSE;
|
||||
s_FifoShuttingDown = FALSE;
|
||||
s_swapRequested = FALSE;
|
||||
|
||||
// VideoCommon
|
||||
DLCache::Shutdown();
|
||||
Fifo_Shutdown();
|
||||
CommandProcessor::Shutdown();
|
||||
PixelShaderManager::Shutdown();
|
||||
VertexShaderManager::Shutdown();
|
||||
OpcodeDecoder_Shutdown();
|
||||
VertexLoaderManager::Shutdown();
|
||||
|
||||
// internal interfaces
|
||||
D3D::ShutdownUtils();
|
||||
PixelShaderCache::Shutdown();
|
||||
VertexShaderCache::Shutdown();
|
||||
delete g_perf_query;
|
||||
delete g_vertex_manager;
|
||||
delete g_texture_cache;
|
||||
delete g_renderer;
|
||||
g_renderer = NULL;
|
||||
g_texture_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBackend::Video_Cleanup() {
|
||||
}
|
||||
|
||||
}
|
||||
11
Source/Core/VideoBackends/D3D/Src/main.h
Normal file
11
Source/Core/VideoBackends/D3D/Src/main.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include "Render.h"
|
||||
#include "MainBase.h"
|
||||
|
||||
#endif
|
||||
5
Source/Core/VideoBackends/D3D/Src/stdafx.cpp
Normal file
5
Source/Core/VideoBackends/D3D/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"
|
||||
12
Source/Core/VideoBackends/D3D/Src/stdafx.h
Normal file
12
Source/Core/VideoBackends/D3D/Src/stdafx.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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>
|
||||
51
Source/Core/VideoBackends/OGL/CMakeLists.txt
Normal file
51
Source/Core/VideoBackends/OGL/CMakeLists.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
set(SRCS Src/FramebufferManager.cpp
|
||||
Src/GLUtil.cpp
|
||||
Src/main.cpp
|
||||
Src/NativeVertexFormat.cpp
|
||||
Src/PerfQuery.cpp
|
||||
Src/PixelShaderCache.cpp
|
||||
Src/PostProcessing.cpp
|
||||
Src/ProgramShaderCache.cpp
|
||||
Src/RasterFont.cpp
|
||||
Src/Render.cpp
|
||||
Src/SamplerCache.cpp
|
||||
Src/StreamBuffer.cpp
|
||||
Src/TextureCache.cpp
|
||||
Src/TextureConverter.cpp
|
||||
Src/VertexShaderCache.cpp
|
||||
Src/VertexManager.cpp)
|
||||
|
||||
set(LIBS videocommon
|
||||
SOIL
|
||||
common
|
||||
${X11_LIBRARIES})
|
||||
if(USE_EGL)
|
||||
set(LIBS ${LIBS}
|
||||
EGL)
|
||||
endif()
|
||||
|
||||
if(USE_GLES3)
|
||||
set(LIBS ${LIBS}
|
||||
GLESv2)
|
||||
set(SRCS ${SRCS} Src/GLFunctions.cpp)
|
||||
else()
|
||||
set(LIBS ${LIBS}
|
||||
GLEW
|
||||
${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(wxWidgets_FOUND)
|
||||
set(LIBS ${LIBS} ${wxWidgets_LIBRARIES})
|
||||
endif(wxWidgets_FOUND)
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(LIBS ${LIBS} clrun)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" OR
|
||||
${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
set(LIBS ${LIBS} usbhid)
|
||||
endif()
|
||||
|
||||
add_library(videoogl STATIC ${SRCS})
|
||||
target_link_libraries(videoogl ${LIBS})
|
||||
250
Source/Core/VideoBackends/OGL/OGL.vcxproj
Normal file
250
Source/Core/VideoBackends/OGL/OGL.vcxproj
Normal file
@@ -0,0 +1,250 @@
|
||||
<?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>{1909CD2D-1707-456F-86CA-0DF42A727C99}</ProjectGuid>
|
||||
<RootNamespace>VideoOGL</RootNamespace>
|
||||
<ProjectName>VideoOGL</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)'=='DebugFast|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<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)'=='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)'=='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|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)'=='DebugFast|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\GLew\include;..\..\..\Externals;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Lib />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\FramebufferManager.cpp" />
|
||||
<ClCompile Include="Src\GLUtil.cpp" />
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp" />
|
||||
<ClCompile Include="Src\PerfQuery.cpp" />
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp" />
|
||||
<ClCompile Include="Src\PostProcessing.cpp" />
|
||||
<ClCompile Include="Src\ProgramShaderCache.cpp" />
|
||||
<ClCompile Include="Src\RasterFont.cpp" />
|
||||
<ClCompile Include="Src\Render.cpp" />
|
||||
<ClCompile Include="Src\SamplerCache.cpp" />
|
||||
<ClCompile Include="Src\StreamBuffer.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\TextureCache.cpp" />
|
||||
<ClCompile Include="Src\TextureConverter.cpp" />
|
||||
<ClCompile Include="Src\VertexManager.cpp" />
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\FramebufferManager.h" />
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\GLUtil.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\PerfQuery.h" />
|
||||
<ClInclude Include="Src\PostProcessing.h" />
|
||||
<ClInclude Include="Src\ProgramShaderCache.h" />
|
||||
<ClInclude Include="Src\RasterFont.h" />
|
||||
<ClInclude Include="Src\Render.h" />
|
||||
<ClInclude Include="Src\SamplerCache.h" />
|
||||
<ClInclude Include="Src\StreamBuffer.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\TextureCache.h" />
|
||||
<ClInclude Include="Src\TextureConverter.h" />
|
||||
<ClInclude Include="Src\VertexManager.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Externals\zlib\zlib.vcxproj">
|
||||
<Project>{3e1339f5-9311-4122-9442-369702e8fcad}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Core\VideoCommon\VideoCommon.vcxproj">
|
||||
<Project>{3e5c4e02-1ba9-4776-bdbe-e3f91ffa34cf}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
102
Source/Core/VideoBackends/OGL/OGL.vcxproj.filters
Normal file
102
Source/Core/VideoBackends/OGL/OGL.vcxproj.filters
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Src\main.cpp" />
|
||||
<ClCompile Include="Src\stdafx.cpp" />
|
||||
<ClCompile Include="Src\NativeVertexFormat.cpp">
|
||||
<Filter>Decoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\VertexManager.cpp">
|
||||
<Filter>Decoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\GLUtil.cpp">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\TextureConverter.cpp">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\RasterFont.cpp">
|
||||
<Filter>Logging</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\FramebufferManager.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PixelShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PostProcessing.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\ProgramShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\StreamBuffer.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\PerfQuery.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
<ClInclude Include="Src\main.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\VertexManager.h">
|
||||
<Filter>Decoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\GLUtil.h">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\TextureConverter.h">
|
||||
<Filter>GLUtil</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\RasterFont.h">
|
||||
<Filter>Logging</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\FramebufferManager.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PostProcessing.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\ProgramShaderCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Render.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\PerfQuery.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Decoder">
|
||||
<UniqueIdentifier>{a0bb3390-6085-4d10-af48-b60eb4c920e7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GLUtil">
|
||||
<UniqueIdentifier>{5b16573b-fb79-4a51-aa7a-d760df844128}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Logging">
|
||||
<UniqueIdentifier>{14fca297-ab2f-4686-855f-65ab18602248}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Render">
|
||||
<UniqueIdentifier>{aaa16061-dca9-4155-be44-f77538e839fc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
488
Source/Core/VideoBackends/OGL/Src/FramebufferManager.cpp
Normal file
488
Source/Core/VideoBackends/OGL/Src/FramebufferManager.cpp
Normal file
@@ -0,0 +1,488 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Globals.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "GLFunctions.h"
|
||||
|
||||
#include "TextureConverter.h"
|
||||
#include "Render.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
int FramebufferManager::m_targetWidth;
|
||||
int FramebufferManager::m_targetHeight;
|
||||
int FramebufferManager::m_msaaSamples;
|
||||
int FramebufferManager::m_msaaCoverageSamples;
|
||||
|
||||
GLuint FramebufferManager::m_efbFramebuffer;
|
||||
GLuint FramebufferManager::m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
|
||||
GLuint FramebufferManager::m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
|
||||
|
||||
// Only used in MSAA mode.
|
||||
GLuint FramebufferManager::m_resolvedFramebuffer;
|
||||
GLuint FramebufferManager::m_resolvedColorTexture;
|
||||
GLuint FramebufferManager::m_resolvedDepthTexture;
|
||||
|
||||
GLuint FramebufferManager::m_xfbFramebuffer;
|
||||
|
||||
// reinterpret pixel format
|
||||
GLuint FramebufferManager::m_pixel_format_vao;
|
||||
GLuint FramebufferManager::m_pixel_format_vbo;
|
||||
SHADER FramebufferManager::m_pixel_format_shaders[2];
|
||||
|
||||
|
||||
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
|
||||
{
|
||||
m_efbFramebuffer = 0;
|
||||
m_efbColor = 0;
|
||||
m_efbDepth = 0;
|
||||
m_resolvedFramebuffer = 0;
|
||||
m_resolvedColorTexture = 0;
|
||||
m_resolvedDepthTexture = 0;
|
||||
m_xfbFramebuffer = 0;
|
||||
|
||||
m_targetWidth = targetWidth;
|
||||
m_targetHeight = targetHeight;
|
||||
|
||||
m_msaaSamples = msaaSamples;
|
||||
m_msaaCoverageSamples = msaaCoverageSamples;
|
||||
|
||||
// The EFB can be set to different pixel formats by the game through the
|
||||
// BPMEM_ZCOMPARE register (which should probably have a different name).
|
||||
// They are:
|
||||
// - 24-bit RGB (8-bit components) with 24-bit Z
|
||||
// - 24-bit RGBA (6-bit components) with 24-bit Z
|
||||
// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
|
||||
// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
|
||||
// Multisampling depends on user settings.
|
||||
// The distinction becomes important for certain operations, i.e. the
|
||||
// alpha channel should be ignored if the EFB does not have one.
|
||||
|
||||
// Create EFB target.
|
||||
|
||||
glGenFramebuffers(1, &m_efbFramebuffer);
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
// EFB targets will be textures in non-MSAA mode.
|
||||
|
||||
GLuint glObj[3];
|
||||
glGenTextures(3, glObj);
|
||||
m_efbColor = glObj[0];
|
||||
m_efbDepth = glObj[1];
|
||||
m_resolvedColorTexture = glObj[2]; // needed for pixel format convertion
|
||||
|
||||
glBindTexture(getFbType(), m_efbColor);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(getFbType(), m_efbDepth);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
glBindTexture(getFbType(), m_resolvedColorTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
// Bind target textures to the EFB framebuffer.
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getFbType(), m_efbColor, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, getFbType(), m_efbDepth, 0);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
}
|
||||
else
|
||||
{
|
||||
// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
|
||||
// Resolve targets will be created to transfer EFB to RAM textures.
|
||||
// XFB framebuffer will be created to transfer EFB to XFB texture.
|
||||
|
||||
// Create EFB target renderbuffers.
|
||||
|
||||
GLuint glObj[2];
|
||||
glGenRenderbuffers(2, glObj);
|
||||
m_efbColor = glObj[0];
|
||||
m_efbDepth = glObj[1];
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_efbColor);
|
||||
if (m_msaaCoverageSamples)
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
else
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_efbDepth);
|
||||
if (m_msaaCoverageSamples)
|
||||
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
else
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
// Bind target renderbuffers to EFB framebuffer.
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_efbColor);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_efbDepth);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
// Create resolved targets for transferring multisampled EFB to texture.
|
||||
|
||||
glGenFramebuffers(1, &m_resolvedFramebuffer);
|
||||
|
||||
glGenTextures(2, glObj);
|
||||
m_resolvedColorTexture = glObj[0];
|
||||
m_resolvedDepthTexture = glObj[1];
|
||||
|
||||
glBindTexture(getFbType(), m_resolvedColorTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glBindTexture(getFbType(), m_resolvedDepthTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(getFbType(), 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
|
||||
|
||||
// Bind resolved textures to resolved framebuffer.
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getFbType(), m_resolvedColorTexture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, getFbType(), m_resolvedDepthTexture, 0);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
// Return to EFB framebuffer.
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
}
|
||||
// Create XFB framebuffer; targets will be created elsewhere.
|
||||
|
||||
glGenFramebuffers(1, &m_xfbFramebuffer);
|
||||
|
||||
// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
|
||||
glViewport(0, 0, m_targetWidth, m_targetHeight);
|
||||
glScissor(0, 0, m_targetWidth, m_targetHeight);
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
glClearDepthf(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// reinterpret pixel format
|
||||
glGenBuffers(1, &m_pixel_format_vbo);
|
||||
glGenVertexArrays(1, &m_pixel_format_vao);
|
||||
glBindVertexArray(m_pixel_format_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_pixel_format_vbo);
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*2, NULL);
|
||||
|
||||
float vertices[] = {
|
||||
-1.0, -1.0,
|
||||
1.0, -1.0,
|
||||
-1.0, 1.0,
|
||||
1.0, 1.0,
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
char vs[] =
|
||||
"ATTRIN vec2 rawpos;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
char ps_rgba6_to_rgb8[] =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" ivec4 src6 = ivec4(round(texture2DRect(samp9, gl_FragCoord.xy) * 63.f));\n"
|
||||
" ivec4 dst8;\n"
|
||||
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
|
||||
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
|
||||
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
|
||||
" dst8.a = 255;\n"
|
||||
" ocol0 = float4(dst8) / 255.f;\n"
|
||||
"}";
|
||||
|
||||
char ps_rgb8_to_rgba6[] =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" ivec4 src8 = ivec4(round(texture2DRect(samp9, gl_FragCoord.xy) * 255.f));\n"
|
||||
" ivec4 dst6;\n"
|
||||
" dst6.r = src8.r >> 2;\n"
|
||||
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
|
||||
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
|
||||
" dst6.a = src8.b & 0x3F;\n"
|
||||
" ocol0 = float4(dst6) / 63.f;\n"
|
||||
"}";
|
||||
|
||||
if(g_ogl_config.eSupportedGLSLVersion != GLSLES2)
|
||||
{
|
||||
// HACK: This shaders aren't glsles2 compatible as glsles2 don't support bit operations
|
||||
// it could be workaround by floor + frac + tons off additions, but I think it isn't worth
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6);
|
||||
ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8);
|
||||
}
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
GLuint glObj[3];
|
||||
|
||||
// Note: OpenGL deletion functions silently ignore parameters of "0".
|
||||
|
||||
glObj[0] = m_efbFramebuffer;
|
||||
glObj[1] = m_resolvedFramebuffer;
|
||||
glObj[2] = m_xfbFramebuffer;
|
||||
glDeleteFramebuffers(3, glObj);
|
||||
m_efbFramebuffer = 0;
|
||||
m_xfbFramebuffer = 0;
|
||||
|
||||
glObj[0] = m_resolvedColorTexture;
|
||||
glObj[1] = m_resolvedDepthTexture;
|
||||
glDeleteTextures(2, glObj);
|
||||
m_resolvedColorTexture = 0;
|
||||
m_resolvedDepthTexture = 0;
|
||||
|
||||
glObj[0] = m_efbColor;
|
||||
glObj[1] = m_efbDepth;
|
||||
if (m_msaaSamples <= 1)
|
||||
glDeleteTextures(2, glObj);
|
||||
else
|
||||
glDeleteRenderbuffers(2, glObj);
|
||||
m_efbColor = 0;
|
||||
m_efbDepth = 0;
|
||||
|
||||
// reinterpret pixel format
|
||||
glDeleteVertexArrays(1, &m_pixel_format_vao);
|
||||
glDeleteBuffers(1, &m_pixel_format_vbo);
|
||||
m_pixel_format_shaders[0].Destroy();
|
||||
m_pixel_format_shaders[1].Destroy();
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc)
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
return m_efbColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
||||
// required.
|
||||
|
||||
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
glBlitFramebuffer(
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
return m_resolvedColorTexture;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc)
|
||||
{
|
||||
if (m_msaaSamples <= 1)
|
||||
{
|
||||
return m_efbDepth;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
|
||||
// required.
|
||||
|
||||
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight);
|
||||
|
||||
// Resolve.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
glBlitFramebuffer(
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
|
||||
GL_DEPTH_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
return m_resolvedDepthTexture;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
|
||||
{
|
||||
u8* xfb_in_ram = Memory::GetPointer(xfbAddr);
|
||||
if (!xfb_in_ram)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
|
||||
return;
|
||||
}
|
||||
|
||||
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
void FramebufferManager::SetFramebuffer(GLuint fb)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer());
|
||||
}
|
||||
|
||||
// Apply AA if enabled
|
||||
GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle &source_rect)
|
||||
{
|
||||
return GetEFBColorTexture(source_rect);
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_rect)
|
||||
{
|
||||
return GetEFBDepthTexture(source_rect);
|
||||
}
|
||||
|
||||
void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
|
||||
{
|
||||
if(g_ogl_config.eSupportedGLSLVersion == GLSLES2) {
|
||||
// This feature isn't supported by glsles2
|
||||
|
||||
// TODO: move this to InitBackendInfo
|
||||
// We have to disable both the active and the stored config. Else we
|
||||
// would either
|
||||
// show this line per format change in one frame or
|
||||
// once per frame.
|
||||
OSD::AddMessage("Format Change Emulation isn't supported by your GPU.", 10000);
|
||||
g_ActiveConfig.bEFBEmulateFormatChanges = false;
|
||||
g_Config.bEFBEmulateFormatChanges = false;
|
||||
return;
|
||||
}
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
GLuint src_texture = 0;
|
||||
|
||||
if(m_msaaSamples > 1)
|
||||
{
|
||||
// MSAA mode, so resolve first
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
|
||||
glBlitFramebuffer(
|
||||
0, 0, m_targetWidth, m_targetHeight,
|
||||
0, 0, m_targetWidth, m_targetHeight,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_efbFramebuffer);
|
||||
|
||||
src_texture = m_resolvedColorTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-MSAA mode, so switch textures
|
||||
src_texture = m_efbColor;
|
||||
m_efbColor = m_resolvedColorTexture;
|
||||
m_resolvedColorTexture = src_texture;
|
||||
|
||||
// also switch them on fbo
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, getFbType(), m_efbColor, 0);
|
||||
}
|
||||
glViewport(0,0, m_targetWidth, m_targetHeight);
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
glBindTexture(getFbType(), src_texture);
|
||||
|
||||
m_pixel_format_shaders[convtype ? 1 : 0].Bind();
|
||||
glBindVertexArray(m_pixel_format_vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
XFBSource::~XFBSource()
|
||||
{
|
||||
glDeleteTextures(1, &texture);
|
||||
}
|
||||
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
|
||||
{
|
||||
// Texture map xfbSource->texture onto the main buffer
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
glBlitFramebuffer(sourcerc.left, sourcerc.bottom, sourcerc.right, sourcerc.top,
|
||||
drawrc.left, drawrc.bottom, drawrc.right, drawrc.top,
|
||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture);
|
||||
}
|
||||
|
||||
void XFBSource::CopyEFB(float Gamma)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// Copy EFB data to XFB and restore render target again
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer());
|
||||
|
||||
// Bind texture.
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
glBlitFramebuffer(
|
||||
0, 0, texWidth, texHeight,
|
||||
0, 0, texWidth, texHeight,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
);
|
||||
|
||||
// Return to EFB.
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
}
|
||||
|
||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
||||
{
|
||||
GLuint texture;
|
||||
|
||||
glGenTextures(1, &texture);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, target_width, target_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
return new XFBSource(texture);
|
||||
}
|
||||
|
||||
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)
|
||||
{
|
||||
*width = m_targetWidth;
|
||||
*height = m_targetHeight;
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
131
Source/Core/VideoBackends/OGL/Src/FramebufferManager.h
Normal file
131
Source/Core/VideoBackends/OGL/Src/FramebufferManager.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _FRAMEBUFFERMANAGER_H_
|
||||
#define _FRAMEBUFFERMANAGER_H_
|
||||
|
||||
#include "GLUtil.h"
|
||||
#include "FramebufferManagerBase.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "Render.h"
|
||||
|
||||
// On the GameCube, the game sends a request for the graphics processor to
|
||||
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
|
||||
// called the XFB (External Framebuffer). The size and location of the XFB is
|
||||
// decided at the time of the copy, and the format is always YUYV. The video
|
||||
// interface is given a pointer to the XFB, which will be decoded and
|
||||
// displayed on the TV.
|
||||
//
|
||||
// There are two ways for Dolphin to emulate this:
|
||||
//
|
||||
// Real XFB mode:
|
||||
//
|
||||
// Dolphin will behave like the GameCube and encode the EFB to
|
||||
// a portion of GameCube RAM. The emulated video interface will decode the data
|
||||
// for output to the screen.
|
||||
//
|
||||
// Advantages: Behaves exactly like the GameCube.
|
||||
// Disadvantages: Resolution will be limited.
|
||||
//
|
||||
// Virtual XFB mode:
|
||||
//
|
||||
// When a request is made to copy the EFB to an XFB, Dolphin
|
||||
// will remember the RAM location and size of the XFB in a Virtual XFB list.
|
||||
// The video interface will look up the XFB in the list and use the enhanced
|
||||
// data stored there, if available.
|
||||
//
|
||||
// Advantages: Enables high resolution graphics, better than real hardware.
|
||||
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
|
||||
// possible but uncommon), the Virtual XFB will not capture this information.
|
||||
|
||||
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
|
||||
// virtualize.
|
||||
|
||||
namespace OGL {
|
||||
|
||||
struct XFBSource : public XFBSourceBase
|
||||
{
|
||||
XFBSource(GLuint tex) : texture(tex) {}
|
||||
~XFBSource();
|
||||
|
||||
void CopyEFB(float Gamma);
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
void Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
|
||||
|
||||
const GLuint texture;
|
||||
};
|
||||
|
||||
inline GLenum getFbType()
|
||||
{
|
||||
#ifndef USE_GLES3
|
||||
return GL_TEXTURE_RECTANGLE;
|
||||
#endif
|
||||
return GL_TEXTURE_2D;
|
||||
}
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
|
||||
~FramebufferManager();
|
||||
|
||||
// To get the EFB in texture form, these functions may have to transfer
|
||||
// the EFB to a resolved texture first.
|
||||
static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc);
|
||||
static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc);
|
||||
|
||||
static GLuint GetEFBFramebuffer() { return m_efbFramebuffer; }
|
||||
static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; }
|
||||
|
||||
// Resolved framebuffer is only used in MSAA mode.
|
||||
static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer; }
|
||||
|
||||
static void SetFramebuffer(GLuint fb);
|
||||
|
||||
// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID.
|
||||
// Thus, this call may be expensive. Don't repeat it unnecessarily.
|
||||
// If not in MSAA mode, will just return the render target texture ID.
|
||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
||||
static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect);
|
||||
|
||||
// Same as above but for the depth Target.
|
||||
// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to.
|
||||
static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect);
|
||||
|
||||
// Convert EFB content on pixel format change.
|
||||
// convtype=0 -> rgb8->rgba6, convtype=2 -> rgba6->rgb8
|
||||
static void ReinterpretPixelData(unsigned int convtype);
|
||||
|
||||
private:
|
||||
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
||||
void GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc);
|
||||
|
||||
void CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma);
|
||||
|
||||
static int m_targetWidth;
|
||||
static int m_targetHeight;
|
||||
static int m_msaaSamples;
|
||||
static int m_msaaCoverageSamples;
|
||||
|
||||
static GLuint m_efbFramebuffer;
|
||||
static GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
|
||||
static GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
|
||||
|
||||
// Only used in MSAA mode and to convert pixel format
|
||||
static GLuint m_resolvedFramebuffer; // will be hot swapped with m_efbColor on non-msaa pixel format change
|
||||
static GLuint m_resolvedColorTexture;
|
||||
static GLuint m_resolvedDepthTexture;
|
||||
|
||||
static GLuint m_xfbFramebuffer; // Only used in MSAA mode
|
||||
|
||||
// For pixel format draw
|
||||
static GLuint m_pixel_format_vbo;
|
||||
static GLuint m_pixel_format_vao;
|
||||
static SHADER m_pixel_format_shaders[2];
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
|
||||
#endif
|
||||
138
Source/Core/VideoBackends/OGL/Src/GLFunctions.cpp
Normal file
138
Source/Core/VideoBackends/OGL/Src/GLFunctions.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DriverDetails.h"
|
||||
#include "GLFunctions.h"
|
||||
#include "Log.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef USE_GLES3
|
||||
PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
||||
PFNGLUNMAPBUFFERPROC glUnmapBuffer;
|
||||
PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
|
||||
|
||||
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
|
||||
PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
|
||||
PFNGLDELETESYNCPROC glDeleteSync;
|
||||
PFNGLFENCESYNCPROC glFenceSync;
|
||||
|
||||
PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf;
|
||||
PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri;
|
||||
PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv;
|
||||
PFNGLBINDSAMPLERPROC glBindSampler;
|
||||
PFNGLDELETESAMPLERSPROC glDeleteSamplers;
|
||||
PFNGLGENSAMPLERSPROC glGenSamplers;
|
||||
|
||||
PFNGLGETPROGRAMBINARYPROC glGetProgramBinary;
|
||||
PFNGLPROGRAMBINARYPROC glProgramBinary;
|
||||
PFNGLPROGRAMPARAMETERIPROC glProgramParameteri;
|
||||
|
||||
PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
|
||||
|
||||
PFNGLRENDERBUFFERSTORAGEMULTISAMPLE glRenderbufferStorageMultisample;
|
||||
|
||||
PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
|
||||
PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
|
||||
|
||||
PFNGLBEGINQUERYPROC glBeginQuery;
|
||||
PFNGLENDQUERYPROC glEndQuery;
|
||||
PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv;
|
||||
PFNGLDELETEQUERIESPROC glDeleteQueries;
|
||||
PFNGLGENQUERIESPROC glGenQueries;
|
||||
#endif
|
||||
namespace GLFunc
|
||||
{
|
||||
void *self;
|
||||
void LoadFunction(const char *name, void **func)
|
||||
{
|
||||
#ifdef USE_GLES3
|
||||
*func = (void*)eglGetProcAddress(name);
|
||||
if (*func == NULL)
|
||||
{
|
||||
// Fall back to trying dlsym
|
||||
if (self) // Just in case dlopen fails
|
||||
*func = dlsym(self, name);
|
||||
if (*func == NULL)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Couldn't load function %s", name);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
self = dlopen(NULL, RTLD_LAZY);
|
||||
|
||||
LoadFunction("glUnmapBuffer", (void**)&glUnmapBuffer);
|
||||
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
{
|
||||
LoadFunction("glBeginQueryEXT", (void**)&glBeginQuery);
|
||||
LoadFunction("glEndQueryEXT", (void**)&glEndQuery);
|
||||
LoadFunction("glGetQueryObjectuivEXT", (void**)&glGetQueryObjectuiv);
|
||||
LoadFunction("glDeleteQueriesEXT", (void**)&glDeleteQueries);
|
||||
LoadFunction("glGenQueriesEXT", (void**)&glGenQueries);
|
||||
|
||||
LoadFunction("glMapBufferRangeNV", (void**)&glMapBufferRange);
|
||||
LoadFunction("glBindBufferRangeNV", (void**)&glBindBufferRange);
|
||||
LoadFunction("glBlitFramebufferNV", (void**)&glBlitFramebuffer);
|
||||
|
||||
LoadFunction("glGenVertexArraysOES", (void**)&glGenVertexArrays);
|
||||
LoadFunction("glDeleteVertexArraysOES", (void**)&glDeleteVertexArrays);
|
||||
LoadFunction("glBindVertexArrayOES", (void**)&glBindVertexArray);
|
||||
|
||||
LoadFunction("glRenderbufferStorageMultisampleNV", (void**)&glRenderbufferStorageMultisample);
|
||||
|
||||
LoadFunction("glGetUniformBlockIndexNV", (void**)&glGetUniformBlockIndex);
|
||||
LoadFunction("glUniformBlockBindingNV", (void**)&glUniformBlockBinding);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadFunction("glBeginQuery", (void**)&glBeginQuery);
|
||||
LoadFunction("glEndQuery", (void**)&glEndQuery);
|
||||
LoadFunction("glGetQueryObjectuiv", (void**)&glGetQueryObjectuiv);
|
||||
LoadFunction("glDeleteQueries", (void**)&glDeleteQueries);
|
||||
LoadFunction("glGenQueries", (void**)&glGenQueries);
|
||||
|
||||
LoadFunction("glMapBufferRange", (void**)&glMapBufferRange);
|
||||
LoadFunction("glBindBufferRange", (void**)&glBindBufferRange);
|
||||
LoadFunction("glBlitFramebuffer", (void**)&glBlitFramebuffer);
|
||||
|
||||
LoadFunction("glGenVertexArrays", (void**)&glGenVertexArrays);
|
||||
LoadFunction("glDeleteVertexArrays", (void**)&glDeleteVertexArrays);
|
||||
LoadFunction("glBindVertexArray", (void**)&glBindVertexArray);
|
||||
|
||||
LoadFunction("glClientWaitSync", (void**)&glClientWaitSync);
|
||||
LoadFunction("glDeleteSync", (void**)&glDeleteSync);
|
||||
LoadFunction("glFenceSync", (void**)&glFenceSync);
|
||||
|
||||
LoadFunction("glSamplerParameterf", (void**)&glSamplerParameterf);
|
||||
LoadFunction("glSamplerParameteri", (void**)&glSamplerParameteri);
|
||||
LoadFunction("glSamplerParameterfv", (void**)&glSamplerParameterfv);
|
||||
LoadFunction("glBindSampler", (void**)&glBindSampler);
|
||||
LoadFunction("glDeleteSamplers", (void**)&glDeleteSamplers);
|
||||
LoadFunction("glGenSamplers", (void**)&glGenSamplers);
|
||||
|
||||
LoadFunction("glGetProgramBinary", (void**)&glGetProgramBinary);
|
||||
LoadFunction("glProgramBinary", (void**)&glProgramBinary);
|
||||
LoadFunction("glProgramParameteri", (void**)&glProgramParameteri);
|
||||
|
||||
LoadFunction("glDrawRangeElements", (void**)&glDrawRangeElements);
|
||||
|
||||
LoadFunction("glRenderbufferStorageMultisample", (void**)&glRenderbufferStorageMultisample);
|
||||
|
||||
LoadFunction("glGetUniformBlockIndex", (void**)&glGetUniformBlockIndex);
|
||||
LoadFunction("glUniformBlockBinding", (void**)&glUniformBlockBinding);
|
||||
|
||||
}
|
||||
dlclose(self);
|
||||
}
|
||||
}
|
||||
99
Source/Core/VideoBackends/OGL/Src/GLFunctions.h
Normal file
99
Source/Core/VideoBackends/OGL/Src/GLFunctions.h
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
#ifndef GLFUNCTIONS_H_
|
||||
#define GLFUNCTIONS_H_
|
||||
#include "GLInterface.h"
|
||||
|
||||
#ifdef USE_GLES3
|
||||
typedef GLvoid* (*PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
|
||||
typedef GLvoid* (*PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
|
||||
typedef void (*PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
|
||||
typedef GLboolean (*PFNGLUNMAPBUFFERPROC) (GLenum target);
|
||||
|
||||
typedef void (*PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
// VAOS
|
||||
typedef void (*PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
|
||||
typedef void (*PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
|
||||
typedef void (*PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
|
||||
// Sync
|
||||
typedef GLenum (*PFNGLCLIENTWAITSYNCPROC) (GLsync GLsync,GLbitfield flags,GLuint64 timeout);
|
||||
typedef void (*PFNGLDELETESYNCPROC) (GLsync GLsync);
|
||||
typedef GLsync (*PFNGLFENCESYNCPROC) (GLenum condition,GLbitfield flags);
|
||||
|
||||
//Sampler
|
||||
typedef void (*PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
|
||||
typedef void (*PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
|
||||
typedef void (*PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat* params);
|
||||
typedef void (*PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
|
||||
typedef void (*PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint * samplers);
|
||||
typedef void (*PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint* samplers);
|
||||
|
||||
//Program binary
|
||||
typedef void (*PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum *binaryFormat, GLvoid*binary);
|
||||
typedef void (*PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void* binary, GLsizei length);
|
||||
typedef void (*PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
|
||||
|
||||
typedef GLuint (*PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar* uniformBlockName);
|
||||
typedef void (*PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
|
||||
|
||||
//Query
|
||||
typedef void (*PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
|
||||
typedef void (*PFNGLENDQUERYPROC) (GLenum target);
|
||||
typedef void (*PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint* params);
|
||||
typedef void (*PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint* ids);
|
||||
typedef void (*PFNGLGENQUERIESPROC) (GLsizei n, GLuint* ids);
|
||||
|
||||
// glDraw*
|
||||
typedef void (*PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
|
||||
|
||||
// Multisample buffer
|
||||
typedef void (*PFNGLRENDERBUFFERSTORAGEMULTISAMPLE) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
|
||||
// ptrs
|
||||
extern PFNGLBEGINQUERYPROC glBeginQuery;
|
||||
extern PFNGLENDQUERYPROC glEndQuery;
|
||||
extern PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv;
|
||||
extern PFNGLDELETEQUERIESPROC glDeleteQueries;
|
||||
extern PFNGLGENQUERIESPROC glGenQueries;
|
||||
|
||||
extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
|
||||
extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
||||
extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
|
||||
|
||||
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
|
||||
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
|
||||
extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
|
||||
extern PFNGLDELETESYNCPROC glDeleteSync;
|
||||
extern PFNGLFENCESYNCPROC glFenceSync;
|
||||
|
||||
extern PFNGLGETPROGRAMBINARYPROC glGetProgramBinary;
|
||||
extern PFNGLPROGRAMBINARYPROC glProgramBinary;
|
||||
extern PFNGLPROGRAMPARAMETERIPROC glProgramParameteri;
|
||||
|
||||
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
|
||||
|
||||
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLE glRenderbufferStorageMultisample;
|
||||
|
||||
//Sampler
|
||||
extern PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf;
|
||||
extern PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri;
|
||||
extern PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv;
|
||||
extern PFNGLBINDSAMPLERPROC glBindSampler;
|
||||
extern PFNGLDELETESAMPLERSPROC glDeleteSamplers;
|
||||
extern PFNGLGENSAMPLERSPROC glGenSamplers;
|
||||
|
||||
extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
|
||||
extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
|
||||
#endif
|
||||
|
||||
namespace GLFunc
|
||||
{
|
||||
void Init();
|
||||
}
|
||||
#endif
|
||||
174
Source/Core/VideoBackends/OGL/Src/GLUtil.cpp
Normal file
174
Source/Core/VideoBackends/OGL/Src/GLUtil.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Globals.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "IniFile.h"
|
||||
#include "Core.h"
|
||||
#include "Host.h"
|
||||
#include "VideoBackend.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
#include "Render.h"
|
||||
#include "VertexShaderManager.h"
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
GLWindow GLWin;
|
||||
cInterfaceBase *GLInterface;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
// Draw messages on top of the screen
|
||||
unsigned int VideoBackend::PeekMessages()
|
||||
{
|
||||
return GLInterface->PeekMessages();
|
||||
}
|
||||
|
||||
// Show the current FPS
|
||||
void VideoBackend::UpdateFPSDisplay(const char *text)
|
||||
{
|
||||
char temp[100];
|
||||
snprintf(temp, sizeof temp, "%s | OpenGL | %s", scm_rev_str, text);
|
||||
return GLInterface->UpdateFPSDisplay(temp);
|
||||
}
|
||||
|
||||
}
|
||||
void InitInterface()
|
||||
{
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
GLInterface = new cInterfaceEGL;
|
||||
#elif defined(__APPLE__)
|
||||
GLInterface = new cInterfaceAGL;
|
||||
#elif defined(_WIN32)
|
||||
GLInterface = new cInterfaceWGL;
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
GLInterface = new cInterfaceGLX;
|
||||
#endif
|
||||
}
|
||||
|
||||
GLuint OpenGL_CompileProgram ( const char* vertexShader, const char* fragmentShader )
|
||||
{
|
||||
// generate objects
|
||||
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
GLuint programID = glCreateProgram();
|
||||
|
||||
// compile vertex shader
|
||||
glShaderSource(vertexShaderID, 1, &vertexShader, NULL);
|
||||
glCompileShader(vertexShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
GLint Result = GL_FALSE;
|
||||
char stringBuffer[1024];
|
||||
GLsizei stringBufferUsage = 0;
|
||||
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL vertex shader warnings:\n%s%s", stringBuffer, vertexShader);
|
||||
} else if(!Result) {
|
||||
ERROR_LOG(VIDEO, "GLSL vertex shader error:\n%s%s", stringBuffer, vertexShader);
|
||||
} else {
|
||||
DEBUG_LOG(VIDEO, "GLSL vertex shader compiled:\n%s", vertexShader);
|
||||
}
|
||||
bool shader_errors = !Result;
|
||||
#endif
|
||||
|
||||
// compile fragment shader
|
||||
glShaderSource(fragmentShaderID, 1, &fragmentShader, NULL);
|
||||
glCompileShader(fragmentShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(fragmentShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL fragment shader warnings:\n%s%s", stringBuffer, fragmentShader);
|
||||
} else if(!Result) {
|
||||
ERROR_LOG(VIDEO, "GLSL fragment shader error:\n%s%s", stringBuffer, fragmentShader);
|
||||
} else {
|
||||
DEBUG_LOG(VIDEO, "GLSL fragment shader compiled:\n%s", fragmentShader);
|
||||
}
|
||||
shader_errors |= !Result;
|
||||
#endif
|
||||
|
||||
// link them
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &Result);
|
||||
glGetProgramInfoLog(programID, 1024, &stringBufferUsage, stringBuffer);
|
||||
if(Result && stringBufferUsage) {
|
||||
ERROR_LOG(VIDEO, "GLSL linker warnings:\n%s%s%s", stringBuffer, vertexShader, fragmentShader);
|
||||
} else if(!Result && !shader_errors) {
|
||||
ERROR_LOG(VIDEO, "GLSL linker error:\n%s%s%s", stringBuffer, vertexShader, fragmentShader);
|
||||
}
|
||||
#endif
|
||||
|
||||
// cleanup
|
||||
glDeleteShader(vertexShaderID);
|
||||
glDeleteShader(fragmentShaderID);
|
||||
|
||||
return programID;
|
||||
}
|
||||
|
||||
|
||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line)
|
||||
{
|
||||
GLint err = glGetError();
|
||||
if (err != GL_NO_ERROR)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x\n",
|
||||
file, line, function, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void OpenGL_ReportARBProgramError()
|
||||
{
|
||||
#ifndef USE_GLES
|
||||
const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
if (pstr != NULL && pstr[0] != 0)
|
||||
{
|
||||
GLint loc = 0;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
|
||||
ERROR_LOG(VIDEO, "Program error at %d: ", loc);
|
||||
ERROR_LOG(VIDEO, "%s", (char*)pstr);
|
||||
ERROR_LOG(VIDEO, "\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
|
||||
{
|
||||
unsigned int fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (fbo_status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
const char *error = "unknown error";
|
||||
switch (fbo_status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
error = "INCOMPLETE_ATTACHMENT";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
error = "INCOMPLETE_MISSING_ATTACHMENT";
|
||||
break;
|
||||
#ifndef USE_GLES
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
error = "INCOMPLETE_DRAW_BUFFER";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
error = "INCOMPLETE_READ_BUFFER";
|
||||
break;
|
||||
#endif
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
error = "UNSUPPORTED";
|
||||
break;
|
||||
}
|
||||
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n",
|
||||
file, line, function, error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
84
Source/Core/VideoBackends/OGL/Src/GLUtil.h
Normal file
84
Source/Core/VideoBackends/OGL/Src/GLUtil.h
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _GLINIT_H_
|
||||
#define _GLINIT_H_
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "MathUtil.h"
|
||||
#include "GLInterface.h"
|
||||
|
||||
#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils
|
||||
#define GL_DEPTH_STENCIL_EXT 0x84F9
|
||||
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
|
||||
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
|
||||
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLES
|
||||
#define TEX2D GL_TEXTURE_2D
|
||||
#define PREC "highp"
|
||||
#define TEXTYPE "sampler2D"
|
||||
#define TEXFUNC "texture2D"
|
||||
#ifdef USE_GLES3
|
||||
#include "GLFunctions.h"
|
||||
#define GLAPIENTRY GL_APIENTRY
|
||||
#define GL_SAMPLES_PASSED GL_ANY_SAMPLES_PASSED
|
||||
#define GL_READ_ONLY 0x88B8
|
||||
#define GL_WRITE_ONLY 0x88B9
|
||||
#define GL_READ_WRITE 0x88BA
|
||||
#define GL_SRC1_ALPHA 0
|
||||
#define GL_BGRA GL_RGBA
|
||||
#define glDrawElementsBaseVertex(...)
|
||||
#define glDrawRangeElementsBaseVertex(...)
|
||||
#define glRenderbufferStorageMultisampleCoverageNV(...)
|
||||
#endif
|
||||
#else
|
||||
#define TEX2D GL_TEXTURE_RECTANGLE_ARB
|
||||
#define PREC
|
||||
#define TEXTYPE "sampler2DRect"
|
||||
#define TEXFUNC "texture2DRect"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
||||
void InitInterface();
|
||||
|
||||
// Helpers
|
||||
GLuint OpenGL_CompileProgram(const char *vertexShader, const char *fragmentShader);
|
||||
|
||||
// Error reporting - use the convenient macros.
|
||||
void OpenGL_ReportARBProgramError();
|
||||
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line);
|
||||
bool OpenGL_ReportFBOError(const char *function, const char *file, int line);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define GL_REPORT_ERROR() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError(__FUNCTION__, __FILE__, __LINE__)
|
||||
#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError()
|
||||
#else
|
||||
__forceinline GLenum GL_REPORT_ERROR() { return GL_NO_ERROR; }
|
||||
#define GL_REPORT_ERRORD() (void)GL_NO_ERROR
|
||||
#define GL_REPORT_FBO_ERROR() (void)true
|
||||
#define GL_REPORT_PROGRAM_ERROR() (void)0
|
||||
#endif
|
||||
|
||||
// this should be removed in future, but as long as glsl is unstable, we should really read this messages
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define DEBUG_GLSL 1
|
||||
#else
|
||||
#define DEBUG_GLSL 0
|
||||
#endif
|
||||
|
||||
// Isn't defined if we aren't using GLEW 1.6
|
||||
#ifndef GL_ONE_MINUS_SRC1_ALPHA
|
||||
#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
|
||||
#endif
|
||||
|
||||
#endif // _GLINIT_H_
|
||||
13
Source/Core/VideoBackends/OGL/Src/Globals.h
Normal file
13
Source/Core/VideoBackends/OGL/Src/Globals.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _GLOBALS_H_
|
||||
#define _GLOBALS_H_
|
||||
|
||||
#include "Common.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
#endif // _GLOBALS_H_
|
||||
99
Source/Core/VideoBackends/OGL/Src/NativeVertexFormat.cpp
Normal file
99
Source/Core/VideoBackends/OGL/Src/NativeVertexFormat.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "GLUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "x64ABI.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "CPMemory.h"
|
||||
#include "NativeVertexFormat.h"
|
||||
#include "VertexManager.h"
|
||||
|
||||
// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state
|
||||
// machine.
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
|
||||
{
|
||||
return new GLVertexFormat();
|
||||
}
|
||||
|
||||
GLVertexFormat::GLVertexFormat()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GLVertexFormat::~GLVertexFormat()
|
||||
{
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
}
|
||||
|
||||
inline GLuint VarToGL(VarType t)
|
||||
{
|
||||
static const GLuint lookup[5] = {
|
||||
GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT
|
||||
};
|
||||
return lookup[t];
|
||||
}
|
||||
|
||||
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
||||
{
|
||||
this->vtx_decl = _vtx_decl;
|
||||
vertex_stride = vtx_decl.stride;
|
||||
|
||||
// We will not allow vertex components causing uneven strides.
|
||||
if (vertex_stride & 3)
|
||||
PanicAlert("Uneven vertex stride: %i", vertex_stride);
|
||||
|
||||
VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
|
||||
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
// the element buffer is bound directly to the vao, so we must it set for every vao
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->m_index_buffers);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers);
|
||||
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, vtx_decl.stride, (u8*)NULL);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (vtx_decl.num_normals > i) {
|
||||
glEnableVertexAttribArray(SHADER_NORM0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_NORM0_ATTRIB+i, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.normal_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (vtx_decl.color_offset[i] != -1) {
|
||||
glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_COLOR0_ATTRIB+i, 4, GL_UNSIGNED_BYTE, GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.color_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (vtx_decl.texcoord_offset[i] != -1) {
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB+i);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB+i, vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]),
|
||||
GL_FALSE, vtx_decl.stride, (u8*)NULL + vtx_decl.texcoord_offset[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vtx_decl.posmtx_offset != -1) {
|
||||
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (u8*)NULL + vtx_decl.posmtx_offset);
|
||||
}
|
||||
|
||||
vm->m_last_vao = VAO;
|
||||
}
|
||||
|
||||
void GLVertexFormat::SetupVertexPointers() {
|
||||
}
|
||||
|
||||
}
|
||||
154
Source/Core/VideoBackends/OGL/Src/PerfQuery.cpp
Normal file
154
Source/Core/VideoBackends/OGL/Src/PerfQuery.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "RenderBase.h"
|
||||
#include "GLUtil.h"
|
||||
#include "PerfQuery.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
PerfQuery::PerfQuery()
|
||||
: m_query_read_pos()
|
||||
, m_query_count()
|
||||
{
|
||||
for (u32 i = 0; i != ArraySize(m_query_buffer); ++i)
|
||||
glGenQueries(1, &m_query_buffer[i].query_id);
|
||||
|
||||
ResetQuery();
|
||||
}
|
||||
|
||||
PerfQuery::~PerfQuery()
|
||||
{
|
||||
for (u32 i = 0; i != ArraySize(m_query_buffer); ++i)
|
||||
glDeleteQueries(1, &m_query_buffer[i].query_id);
|
||||
}
|
||||
|
||||
void PerfQuery::EnableQuery(PerfQueryGroup type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
// Is this sane?
|
||||
if (m_query_count > ArraySize(m_query_buffer) / 2)
|
||||
WeakFlush();
|
||||
|
||||
if (ArraySize(m_query_buffer) == m_query_count)
|
||||
{
|
||||
FlushOne();
|
||||
//ERROR_LOG(VIDEO, "Flushed query buffer early!");
|
||||
}
|
||||
|
||||
// start query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ArraySize(m_query_buffer)];
|
||||
|
||||
glBeginQuery(GL_SAMPLES_PASSED, entry.query_id);
|
||||
entry.query_type = type;
|
||||
|
||||
++m_query_count;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::DisableQuery(PerfQueryGroup type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
// stop query
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
glEndQuery(GL_SAMPLES_PASSED);
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfQuery::IsFlushed() const
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return true;
|
||||
|
||||
return 0 == m_query_count;
|
||||
}
|
||||
|
||||
void PerfQuery::FlushOne()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
GLuint result = 0;
|
||||
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result);
|
||||
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % ArraySize(m_query_buffer);
|
||||
--m_query_count;
|
||||
}
|
||||
|
||||
// TODO: could selectively flush things, but I don't think that will do much
|
||||
void PerfQuery::FlushResults()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
while (!IsFlushed())
|
||||
FlushOne();
|
||||
}
|
||||
|
||||
void PerfQuery::WeakFlush()
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return;
|
||||
|
||||
while (!IsFlushed())
|
||||
{
|
||||
auto& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
GLuint result = GL_FALSE;
|
||||
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);
|
||||
|
||||
if (GL_TRUE == result)
|
||||
{
|
||||
FlushOne();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::ResetQuery()
|
||||
{
|
||||
m_query_count = 0;
|
||||
std::fill_n(m_results, ArraySize(m_results), 0);
|
||||
}
|
||||
|
||||
u32 PerfQuery::GetQueryResult(PerfQueryType type)
|
||||
{
|
||||
if (!ShouldEmulate())
|
||||
return 0;
|
||||
|
||||
u32 result = 0;
|
||||
|
||||
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP];
|
||||
}
|
||||
else if (type == PQ_BLEND_INPUT)
|
||||
{
|
||||
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
}
|
||||
else if (type == PQ_EFB_COPY_CLOCKS)
|
||||
{
|
||||
result = m_results[PQG_EFB_COPY_CLOCKS];
|
||||
}
|
||||
|
||||
return result / 4;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
46
Source/Core/VideoBackends/OGL/Src/PerfQuery.h
Normal file
46
Source/Core/VideoBackends/OGL/Src/PerfQuery.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _PERFQUERY_H_
|
||||
#define _PERFQUERY_H_
|
||||
|
||||
#include "PerfQueryBase.h"
|
||||
|
||||
namespace OGL {
|
||||
|
||||
class PerfQuery : public PerfQueryBase
|
||||
{
|
||||
public:
|
||||
PerfQuery();
|
||||
~PerfQuery();
|
||||
|
||||
void EnableQuery(PerfQueryGroup type);
|
||||
void DisableQuery(PerfQueryGroup type);
|
||||
void ResetQuery();
|
||||
u32 GetQueryResult(PerfQueryType type);
|
||||
void FlushResults();
|
||||
bool IsFlushed() const;
|
||||
|
||||
private:
|
||||
struct ActiveQuery
|
||||
{
|
||||
GLuint query_id;
|
||||
PerfQueryGroup query_type;
|
||||
};
|
||||
|
||||
// when testing in SMS: 64 was too small, 128 was ok
|
||||
static const u32 PERF_QUERY_BUFFER_SIZE = 512;
|
||||
|
||||
void WeakFlush();
|
||||
// Only use when non-empty
|
||||
void FlushOne();
|
||||
|
||||
// This contains gl query objects with unretrieved results.
|
||||
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
|
||||
u32 m_query_read_pos;
|
||||
|
||||
// TODO: sloppy
|
||||
volatile u32 m_query_count;
|
||||
volatile u32 m_results[PQG_NUM_MEMBERS];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _PERFQUERY_H_
|
||||
104
Source/Core/VideoBackends/OGL/Src/PixelShaderCache.cpp
Normal file
104
Source/Core/VideoBackends/OGL/Src/PixelShaderCache.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Statistics.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "Common.h"
|
||||
#include "Render.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "StringUtil.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
void SetPSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
|
||||
{
|
||||
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
if (!strcmp(name, UniformNames[a]))
|
||||
{
|
||||
if (tmp.shader.UniformLocations[a] == -1)
|
||||
return;
|
||||
else if (tmp.shader.UniformSize[a] <= offset)
|
||||
return;
|
||||
else
|
||||
{
|
||||
unsigned int maxcount= tmp.shader.UniformSize[a]-offset;
|
||||
glUniform4fv(tmp.shader.UniformLocations[a] + offset, std::min(count, maxcount), f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renderer functions
|
||||
void Renderer::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
float const f[4] = {f1, f2, f3, f4};
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetPSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 10; ++a)
|
||||
{
|
||||
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - PSVar_Loc[a].reg;
|
||||
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OGL
|
||||
180
Source/Core/VideoBackends/OGL/Src/PostProcessing.cpp
Normal file
180
Source/Core/VideoBackends/OGL/Src/PostProcessing.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "CommonPaths.h"
|
||||
#include "FileUtil.h"
|
||||
#include "VideoCommon.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "GLUtil.h"
|
||||
#include "PostProcessing.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "FramebufferManager.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
namespace PostProcessing
|
||||
{
|
||||
|
||||
static std::string s_currentShader;
|
||||
static SHADER s_shader;
|
||||
static bool s_enable;
|
||||
|
||||
static u32 s_width;
|
||||
static u32 s_height;
|
||||
static GLuint s_fbo;
|
||||
static GLuint s_texture;
|
||||
static GLuint s_vao;
|
||||
static GLuint s_vbo;
|
||||
|
||||
static GLuint s_uniform_resolution;
|
||||
|
||||
static char s_vertex_shader[] =
|
||||
"in vec2 rawpos;\n"
|
||||
"in vec2 tex0;\n"
|
||||
"out vec2 uv0;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
" uv0 = tex0;\n"
|
||||
"}\n";
|
||||
|
||||
void Init()
|
||||
{
|
||||
s_currentShader = "";
|
||||
s_enable = 0;
|
||||
s_width = 0;
|
||||
s_height = 0;
|
||||
|
||||
glGenFramebuffers(1, &s_fbo);
|
||||
glGenTextures(1, &s_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); // disable mipmaps
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s_fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_texture, 0);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
glGenBuffers(1, &s_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_vbo);
|
||||
GLfloat vertices[] = {
|
||||
-1.f, -1.f, 0.f, 0.f,
|
||||
-1.f, 1.f, 0.f, 1.f,
|
||||
1.f, -1.f, 1.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glGenVertexArrays(1, &s_vao);
|
||||
glBindVertexArray( s_vao );
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
s_shader.Destroy();
|
||||
|
||||
glDeleteFramebuffers(1, &s_vbo);
|
||||
glDeleteTextures(1, &s_texture);
|
||||
|
||||
glDeleteBuffers(1, &s_vbo);
|
||||
glDeleteVertexArrays(1, &s_vao);
|
||||
}
|
||||
|
||||
void ReloadShader()
|
||||
{
|
||||
s_currentShader = "";
|
||||
}
|
||||
|
||||
void BindTargetFramebuffer ()
|
||||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_enable ? s_fbo : 0);
|
||||
}
|
||||
|
||||
void BlitToScreen()
|
||||
{
|
||||
if(!s_enable) return;
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glViewport(0, 0, s_width, s_height);
|
||||
|
||||
glBindVertexArray(s_vao);
|
||||
s_shader.Bind();
|
||||
|
||||
glUniform4f(s_uniform_resolution, (float)s_width, (float)s_height, 1.0f/(float)s_width, 1.0f/(float)s_height);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
/* glBindFramebuffer(GL_READ_FRAMEBUFFER, s_fbo);
|
||||
|
||||
glBlitFramebuffer(rc.left, rc.bottom, rc.right, rc.top,
|
||||
rc.left, rc.bottom, rc.right, rc.top,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);*/
|
||||
}
|
||||
|
||||
void Update ( u32 width, u32 height )
|
||||
{
|
||||
ApplyShader();
|
||||
|
||||
if(s_enable && (width != s_width || height != s_height)) {
|
||||
s_width = width;
|
||||
s_height = height;
|
||||
|
||||
// alloc texture for framebuffer
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyShader()
|
||||
{
|
||||
// shader didn't changed
|
||||
if (s_currentShader == g_ActiveConfig.sPostProcessingShader) return;
|
||||
s_currentShader = g_ActiveConfig.sPostProcessingShader;
|
||||
s_enable = false;
|
||||
s_shader.Destroy();
|
||||
|
||||
// shader disabled
|
||||
if (g_ActiveConfig.sPostProcessingShader == "") return;
|
||||
|
||||
// so need to compile shader
|
||||
|
||||
// loading shader code
|
||||
std::string code;
|
||||
std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".glsl";
|
||||
if (!File::Exists(path))
|
||||
{
|
||||
// Fallback to shared user dir
|
||||
path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + g_ActiveConfig.sPostProcessingShader + ".glsl";
|
||||
}
|
||||
if(!File::ReadFileToString(true, path.c_str(), code)) {
|
||||
ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// and compile it
|
||||
if (!ProgramShaderCache::CompileShader(s_shader, s_vertex_shader, code.c_str())) {
|
||||
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// read uniform locations
|
||||
s_uniform_resolution = glGetUniformLocation(s_shader.glprogid, "resolution");
|
||||
|
||||
// successful
|
||||
s_enable = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace OGL
|
||||
32
Source/Core/VideoBackends/OGL/Src/PostProcessing.h
Normal file
32
Source/Core/VideoBackends/OGL/Src/PostProcessing.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _POSTPROCESSING_H_
|
||||
#define _POSTPROCESSING_H_
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
namespace PostProcessing
|
||||
{
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void BindTargetFramebuffer();
|
||||
void BlitToScreen();
|
||||
void Update(u32 width, u32 height);
|
||||
|
||||
void ReloadShader();
|
||||
|
||||
void ApplyShader();
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // _POSTPROCESSING_H_
|
||||
610
Source/Core/VideoBackends/OGL/Src/ProgramShaderCache.cpp
Normal file
610
Source/Core/VideoBackends/OGL/Src/ProgramShaderCache.cpp
Normal file
@@ -0,0 +1,610 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "DriverDetails.h"
|
||||
#include "MathUtil.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "Debugger.h"
|
||||
#include "Statistics.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "Render.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static const u32 UBO_LENGTH = 32*1024*1024;
|
||||
|
||||
GLintptr ProgramShaderCache::s_vs_data_size;
|
||||
GLintptr ProgramShaderCache::s_ps_data_size;
|
||||
GLintptr ProgramShaderCache::s_vs_data_offset;
|
||||
u8 *ProgramShaderCache::s_ubo_buffer;
|
||||
u32 ProgramShaderCache::s_ubo_buffer_size;
|
||||
bool ProgramShaderCache::s_ubo_dirty;
|
||||
|
||||
static StreamBuffer *s_buffer;
|
||||
static int num_failures = 0;
|
||||
|
||||
LinearDiskCache<SHADERUID, u8> g_program_disk_cache;
|
||||
static GLuint CurrentProgram = 0;
|
||||
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
|
||||
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
|
||||
SHADERUID ProgramShaderCache::last_uid;
|
||||
UidChecker<PixelShaderUid,PixelShaderCode> ProgramShaderCache::pixel_uid_checker;
|
||||
UidChecker<VertexShaderUid,VertexShaderCode> ProgramShaderCache::vertex_uid_checker;
|
||||
|
||||
static char s_glsl_header[1024] = "";
|
||||
|
||||
const char *UniformNames[NUM_UNIFORMS] =
|
||||
{
|
||||
// PIXEL SHADER UNIFORMS
|
||||
I_COLORS,
|
||||
I_KCOLORS,
|
||||
I_ALPHA,
|
||||
I_TEXDIMS,
|
||||
I_ZBIAS ,
|
||||
I_INDTEXSCALE ,
|
||||
I_INDTEXMTX,
|
||||
I_FOG,
|
||||
I_PLIGHTS,
|
||||
I_PMATERIALS,
|
||||
// VERTEX SHADER UNIFORMS
|
||||
I_POSNORMALMATRIX,
|
||||
I_PROJECTION ,
|
||||
I_MATERIALS,
|
||||
I_LIGHTS,
|
||||
I_TEXMATRICES,
|
||||
I_TRANSFORMMATRICES ,
|
||||
I_NORMALMATRICES ,
|
||||
I_POSTTRANSFORMMATRICES,
|
||||
I_DEPTHPARAMS,
|
||||
};
|
||||
|
||||
void SHADER::SetProgramVariables()
|
||||
{
|
||||
// glsl shader must be bind to set samplers
|
||||
Bind();
|
||||
|
||||
// Bind UBO
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock");
|
||||
GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock");
|
||||
|
||||
if(PSBlock_id != -1)
|
||||
glUniformBlockBinding(glprogid, PSBlock_id, 1);
|
||||
if(VSBlock_id != -1)
|
||||
glUniformBlockBinding(glprogid, VSBlock_id, 2);
|
||||
}
|
||||
|
||||
// UBO workaround
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
UniformLocations[a] = glGetUniformLocation(glprogid, UniformNames[a]);
|
||||
UniformSize[a] = 0;
|
||||
if(g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
break;
|
||||
}
|
||||
if(!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
int max_uniforms = 0;
|
||||
char name[50];
|
||||
int size;
|
||||
|
||||
glGetProgramiv(glprogid, GL_ACTIVE_UNIFORMS, &max_uniforms);
|
||||
for(int i=0; i<max_uniforms; i++)
|
||||
{
|
||||
glGetActiveUniform(glprogid, i, sizeof(name), NULL, &size, NULL, name);
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
if(strstr(name, UniformNames[a]))
|
||||
{
|
||||
UniformSize[a] = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bind Texture Sampler
|
||||
for (int a = 0; a <= 9; ++a)
|
||||
{
|
||||
char name[8];
|
||||
snprintf(name, 8, "samp%d", a);
|
||||
|
||||
// Still need to get sampler locations since we aren't binding them statically in the shaders
|
||||
int loc = glGetUniformLocation(glprogid, name);
|
||||
if (loc != -1)
|
||||
glUniform1i(loc, a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SHADER::SetProgramBindings()
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
|
||||
{
|
||||
// So we do support extended blending
|
||||
// So we need to set a few more things here.
|
||||
// Bind our out locations
|
||||
#ifndef USE_GLES3
|
||||
glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0");
|
||||
glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1");
|
||||
#endif
|
||||
}
|
||||
// Need to set some attribute locations
|
||||
glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "fposmtx");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0");
|
||||
glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1");
|
||||
|
||||
glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0");
|
||||
glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1");
|
||||
glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2");
|
||||
|
||||
for(int i=0; i<8; i++) {
|
||||
char attrib_name[8];
|
||||
snprintf(attrib_name, 8, "tex%d", i);
|
||||
glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB+i, attrib_name);
|
||||
}
|
||||
}
|
||||
|
||||
void SHADER::Bind()
|
||||
{
|
||||
if(CurrentProgram != glprogid)
|
||||
{
|
||||
glUseProgram(glprogid);
|
||||
CurrentProgram = glprogid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProgramShaderCache::SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count)
|
||||
{
|
||||
s_ubo_dirty = true;
|
||||
memcpy(s_ubo_buffer+(offset*4*sizeof(float)), f, count*4*sizeof(float));
|
||||
}
|
||||
|
||||
void ProgramShaderCache::SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count)
|
||||
{
|
||||
s_ubo_dirty = true;
|
||||
memcpy(s_ubo_buffer+(offset*4*sizeof(float))+s_vs_data_offset, f, count*4*sizeof(float));
|
||||
}
|
||||
|
||||
void ProgramShaderCache::UploadConstants()
|
||||
{
|
||||
if(s_ubo_dirty) {
|
||||
s_buffer->Alloc(s_ubo_buffer_size);
|
||||
size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_ps_data_size);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_vs_data_size);
|
||||
s_ubo_dirty = false;
|
||||
|
||||
ADDSTAT(stats.thisFrame.bytesUniformStreamed, s_ubo_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint ProgramShaderCache::GetCurrentProgram(void)
|
||||
{
|
||||
return CurrentProgram;
|
||||
}
|
||||
|
||||
SHADER* ProgramShaderCache::SetShader ( DSTALPHA_MODE dstAlphaMode, u32 components )
|
||||
{
|
||||
SHADERUID uid;
|
||||
GetShaderId(&uid, dstAlphaMode, components);
|
||||
|
||||
// Check if the shader is already set
|
||||
if (last_entry)
|
||||
{
|
||||
if (uid == last_uid)
|
||||
{
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
}
|
||||
|
||||
last_uid = uid;
|
||||
|
||||
// Check if shader is already in cache
|
||||
PCache::iterator iter = pshaders.find(uid);
|
||||
if (iter != pshaders.end())
|
||||
{
|
||||
PCacheEntry *entry = &iter->second;
|
||||
last_entry = entry;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
// Make an entry in the table
|
||||
PCacheEntry& newentry = pshaders[uid];
|
||||
last_entry = &newentry;
|
||||
newentry.in_cache = 0;
|
||||
|
||||
VertexShaderCode vcode;
|
||||
PixelShaderCode pcode;
|
||||
GenerateVertexShaderCode(vcode, components, API_OPENGL);
|
||||
GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components);
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
newentry.shader.strvprog = vcode.GetBuffer();
|
||||
newentry.shader.strpprog = pcode.GetBuffer();
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS) {
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
SaveData(szTemp, vcode.GetBuffer());
|
||||
sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
SaveData(szTemp, pcode.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer())) {
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
|
||||
|
||||
last_entry->shader.Bind();
|
||||
return &last_entry->shader;
|
||||
}
|
||||
|
||||
bool ProgramShaderCache::CompileShader ( SHADER& shader, const char* vcode, const char* pcode )
|
||||
{
|
||||
GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode);
|
||||
GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode);
|
||||
|
||||
if(!vsid || !psid)
|
||||
{
|
||||
glDeleteShader(vsid);
|
||||
glDeleteShader(psid);
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint pid = shader.glprogid = glCreateProgram();;
|
||||
|
||||
glAttachShader(pid, vsid);
|
||||
glAttachShader(pid, psid);
|
||||
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
shader.SetProgramBindings();
|
||||
|
||||
glLinkProgram(pid);
|
||||
|
||||
// original shaders aren't needed any more
|
||||
glDeleteShader(vsid);
|
||||
glDeleteShader(psid);
|
||||
|
||||
GLint linkStatus;
|
||||
glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus);
|
||||
GLsizei length = 0;
|
||||
glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length);
|
||||
if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
|
||||
{
|
||||
GLsizei charsWritten;
|
||||
GLchar* infoLog = new GLchar[length];
|
||||
glGetProgramInfoLog(pid, length, &charsWritten, infoLog);
|
||||
ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog);
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << s_glsl_header << vcode << s_glsl_header << pcode << infoLog;
|
||||
file.close();
|
||||
|
||||
if(linkStatus != GL_TRUE)
|
||||
PanicAlert("Failed to link shaders!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s, %s, %s):\n%s",
|
||||
szTemp,
|
||||
g_ogl_config.gl_vendor,
|
||||
g_ogl_config.gl_renderer,
|
||||
g_ogl_config.gl_version,
|
||||
infoLog);
|
||||
|
||||
delete [] infoLog;
|
||||
}
|
||||
if (linkStatus != GL_TRUE)
|
||||
{
|
||||
// Compile failed
|
||||
ERROR_LOG(VIDEO, "Program linking failed; see info log");
|
||||
|
||||
// Don't try to use this shader
|
||||
glDeleteProgram(pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
shader.SetProgramVariables();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint ProgramShaderCache::CompileSingleShader (GLuint type, const char* code )
|
||||
{
|
||||
GLuint result = glCreateShader(type);
|
||||
|
||||
const char *src[] = {s_glsl_header, code};
|
||||
|
||||
glShaderSource(result, 2, src, NULL);
|
||||
glCompileShader(result);
|
||||
GLint compileStatus;
|
||||
glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus);
|
||||
GLsizei length = 0;
|
||||
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_BROKENINFOLOG))
|
||||
length = 1024;
|
||||
|
||||
if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
|
||||
{
|
||||
GLsizei charsWritten;
|
||||
GLchar* infoLog = new GLchar[length];
|
||||
glGetShaderInfoLog(result, length, &charsWritten, infoLog);
|
||||
ERROR_LOG(VIDEO, "PS Shader info log:\n%s", infoLog);
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp,
|
||||
"%sbad_%s_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(),
|
||||
type==GL_VERTEX_SHADER ? "vs" : "ps",
|
||||
num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, szTemp, std::ios_base::out);
|
||||
file << s_glsl_header << code << infoLog;
|
||||
file.close();
|
||||
|
||||
if(compileStatus != GL_TRUE)
|
||||
PanicAlert("Failed to compile %s shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s, %s, %s):\n%s",
|
||||
type==GL_VERTEX_SHADER ? "vertex" : "pixel",
|
||||
szTemp,
|
||||
g_ogl_config.gl_vendor,
|
||||
g_ogl_config.gl_renderer,
|
||||
g_ogl_config.gl_version,
|
||||
infoLog);
|
||||
|
||||
delete[] infoLog;
|
||||
}
|
||||
if (compileStatus != GL_TRUE)
|
||||
{
|
||||
// Compile failed
|
||||
ERROR_LOG(VIDEO, "Shader compilation failed; see info log");
|
||||
|
||||
// Don't try to use this shader
|
||||
glDeleteShader(result);
|
||||
return 0;
|
||||
}
|
||||
(void)GL_REPORT_ERROR();
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components)
|
||||
{
|
||||
GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components);
|
||||
GetVertexShaderUid(uid->vuid, components, API_OPENGL);
|
||||
|
||||
if (g_ActiveConfig.bEnableShaderDebugging)
|
||||
{
|
||||
PixelShaderCode pcode;
|
||||
GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components);
|
||||
pixel_uid_checker.AddToIndexAndCheck(pcode, uid->puid, "Pixel", "p");
|
||||
|
||||
VertexShaderCode vcode;
|
||||
GenerateVertexShaderCode(vcode, components, API_OPENGL);
|
||||
vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v");
|
||||
}
|
||||
}
|
||||
|
||||
ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram(void)
|
||||
{
|
||||
return *last_entry;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::Init(void)
|
||||
{
|
||||
// We have to get the UBO alignment here because
|
||||
// if we generate a buffer that isn't aligned
|
||||
// then the UBO will fail.
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
GLint Align;
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &Align);
|
||||
|
||||
s_ps_data_size = C_PENVCONST_END * sizeof(float) * 4;
|
||||
s_vs_data_size = C_VENVCONST_END * sizeof(float) * 4;
|
||||
s_vs_data_offset = ROUND_UP(s_ps_data_size, Align);
|
||||
s_ubo_buffer_size = ROUND_UP(s_ps_data_size, Align) + ROUND_UP(s_vs_data_size, Align);
|
||||
|
||||
// We multiply by *4*4 because we need to get down to basic machine units.
|
||||
// So multiply by four to get how many floats we have from vec4s
|
||||
// Then once more to get bytes
|
||||
s_buffer = new StreamBuffer(GL_UNIFORM_BUFFER, UBO_LENGTH);
|
||||
|
||||
s_ubo_buffer = new u8[s_ubo_buffer_size];
|
||||
memset(s_ubo_buffer, 0, s_ubo_buffer_size);
|
||||
s_ubo_dirty = true;
|
||||
}
|
||||
|
||||
// Read our shader cache, only if supported
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
{
|
||||
GLint Supported;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
|
||||
if(!Supported)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So disable shader cache.");
|
||||
g_ogl_config.bSupportsGLSLCache = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
|
||||
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
||||
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
|
||||
|
||||
ProgramShaderCacheInserter inserter;
|
||||
g_program_disk_cache.OpenAndRead(cache_filename, inserter);
|
||||
}
|
||||
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
|
||||
}
|
||||
|
||||
CreateHeader();
|
||||
|
||||
CurrentProgram = 0;
|
||||
last_entry = NULL;
|
||||
}
|
||||
|
||||
void ProgramShaderCache::Shutdown(void)
|
||||
{
|
||||
// store all shaders in cache on disk
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
{
|
||||
PCache::iterator iter = pshaders.begin();
|
||||
for (; iter != pshaders.end(); ++iter)
|
||||
{
|
||||
if(iter->second.in_cache) continue;
|
||||
|
||||
GLint binary_size;
|
||||
glGetProgramiv(iter->second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
|
||||
if(!binary_size) continue;
|
||||
|
||||
u8 *data = new u8[binary_size+sizeof(GLenum)];
|
||||
u8 *binary = data + sizeof(GLenum);
|
||||
GLenum *prog_format = (GLenum*)data;
|
||||
glGetProgramBinary(iter->second.shader.glprogid, binary_size, NULL, prog_format, binary);
|
||||
|
||||
g_program_disk_cache.Append(iter->first, data, binary_size+sizeof(GLenum));
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
g_program_disk_cache.Sync();
|
||||
g_program_disk_cache.Close();
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
PCache::iterator iter = pshaders.begin();
|
||||
for (; iter != pshaders.end(); ++iter)
|
||||
iter->second.Destroy();
|
||||
pshaders.clear();
|
||||
|
||||
pixel_uid_checker.Invalidate();
|
||||
vertex_uid_checker.Invalidate();
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
delete s_buffer;
|
||||
s_buffer = 0;
|
||||
delete [] s_ubo_buffer;
|
||||
s_ubo_buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ProgramShaderCache::CreateHeader ( void )
|
||||
{
|
||||
GLSL_VERSION v = g_ogl_config.eSupportedGLSLVersion;
|
||||
snprintf(s_glsl_header, sizeof(s_glsl_header),
|
||||
"%s\n"
|
||||
"%s\n" // ubo
|
||||
"%s\n" // early-z
|
||||
|
||||
// Precision defines for GLSLES2/3
|
||||
"%s\n"
|
||||
|
||||
"\n"// A few required defines and ones that will make our lives a lot easier
|
||||
"#define ATTRIN %s\n"
|
||||
"#define ATTROUT %s\n"
|
||||
"#define VARYIN %s\n"
|
||||
"#define VARYOUT %s\n"
|
||||
|
||||
// Silly differences
|
||||
"#define float2 vec2\n"
|
||||
"#define float3 vec3\n"
|
||||
"#define float4 vec4\n"
|
||||
|
||||
// hlsl to glsl function translation
|
||||
"#define frac fract\n"
|
||||
"#define lerp mix\n"
|
||||
|
||||
// texture2d hack
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
|
||||
// GLSLES2 hacks
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"%s\n"
|
||||
"#define COLOROUT(name) %s\n"
|
||||
|
||||
|
||||
, v==GLSLES2 ? "" : v==GLSLES3 ? "#version 300 es" : v==GLSL_130 ? "#version 130" : v==GLSL_140 ? "#version 140" : "#version 150"
|
||||
, g_ActiveConfig.backend_info.bSupportsGLSLUBO && v<GLSL_140 ? "#extension GL_ARB_uniform_buffer_object : enable" : ""
|
||||
, g_ActiveConfig.backend_info.bSupportsEarlyZ ? "#extension GL_ARB_shader_image_load_store : enable" : ""
|
||||
|
||||
, (v==GLSLES3 || v==GLSLES2) ? "precision highp float;" : ""
|
||||
|
||||
, v==GLSLES2 ? "attribute" : "in"
|
||||
, v==GLSLES2 ? "attribute" : "out"
|
||||
, v==GLSLES2 ? "varying" : DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "in" : "centroid in"
|
||||
, v==GLSLES2 ? "varying" : DriverDetails::HasBug(DriverDetails::BUG_BROKENCENTROID) ? "out" : "centroid out"
|
||||
|
||||
, v==GLSLES2 ? "#define texture2DRect texture2D" : v==GLSLES3 ? "" : v<=GLSL_130 ? "#extension GL_ARB_texture_rectangle : enable" : "#define texture2DRect texture"
|
||||
, v==GLSLES3 ? "#define texture2DRect(samp, uv) texelFetch(samp, ivec2(floor(uv)), 0)" : ""
|
||||
, (v==GLSLES3 || v==GLSLES2) ? "#define sampler2DRect sampler2D" : ""
|
||||
|
||||
, v==GLSLES2 ? "#define texture texture2D" : ""
|
||||
, v==GLSLES2 ? "#define round(x) floor((x)+0.5)" : ""
|
||||
, v==GLSLES2 ? "#define out " : ""
|
||||
, v==GLSLES2 ? "#define ocol0 gl_FragColor" : ""
|
||||
, v==GLSLES2 ? "#define ocol1 gl_FragColor" : ""
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA) ? "#extension GL_NV_uniform_buffer_object : enable" : ""
|
||||
, DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA) ? "#extension GL_NV_fragdepth : enable" : ""
|
||||
, v==GLSLES2 ? "" : "out vec4 name;"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void ProgramShaderCache::ProgramShaderCacheInserter::Read ( const SHADERUID& key, const u8* value, u32 value_size )
|
||||
{
|
||||
const u8 *binary = value+sizeof(GLenum);
|
||||
GLenum *prog_format = (GLenum*)value;
|
||||
GLint binary_size = value_size-sizeof(GLenum);
|
||||
|
||||
PCacheEntry entry;
|
||||
entry.in_cache = 1;
|
||||
entry.shader.glprogid = glCreateProgram();
|
||||
glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size);
|
||||
|
||||
GLint success;
|
||||
glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success);
|
||||
|
||||
if (success)
|
||||
{
|
||||
pshaders[key] = entry;
|
||||
entry.shader.SetProgramVariables();
|
||||
}
|
||||
else
|
||||
glDeleteProgram(entry.shader.glprogid);
|
||||
}
|
||||
|
||||
|
||||
} // namespace OGL
|
||||
122
Source/Core/VideoBackends/OGL/Src/ProgramShaderCache.h
Normal file
122
Source/Core/VideoBackends/OGL/Src/ProgramShaderCache.h
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef PROGRAM_SHADER_CACHE_H_
|
||||
#define PROGRAM_SHADER_CACHE_H_
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include "PixelShaderGen.h"
|
||||
#include "VertexShaderGen.h"
|
||||
|
||||
#include "LinearDiskCache.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class SHADERUID
|
||||
{
|
||||
public:
|
||||
VertexShaderUid vuid;
|
||||
PixelShaderUid puid;
|
||||
|
||||
SHADERUID() {}
|
||||
|
||||
SHADERUID(const SHADERUID& r) : vuid(r.vuid), puid(r.puid) {}
|
||||
|
||||
bool operator <(const SHADERUID& r) const
|
||||
{
|
||||
if(puid < r.puid) return true;
|
||||
if(r.puid < puid) return false;
|
||||
if(vuid < r.vuid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator ==(const SHADERUID& r) const
|
||||
{
|
||||
return puid == r.puid && vuid == r.vuid;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const int NUM_UNIFORMS = 19;
|
||||
extern const char *UniformNames[NUM_UNIFORMS];
|
||||
|
||||
struct SHADER
|
||||
{
|
||||
SHADER() : glprogid(0) { }
|
||||
void Destroy()
|
||||
{
|
||||
glDeleteProgram(glprogid);
|
||||
glprogid = 0;
|
||||
}
|
||||
GLuint glprogid; // opengl program id
|
||||
|
||||
std::string strvprog, strpprog;
|
||||
GLint UniformLocations[NUM_UNIFORMS];
|
||||
u32 UniformSize[NUM_UNIFORMS];
|
||||
|
||||
void SetProgramVariables();
|
||||
void SetProgramBindings();
|
||||
void Bind();
|
||||
};
|
||||
|
||||
class ProgramShaderCache
|
||||
{
|
||||
public:
|
||||
|
||||
struct PCacheEntry
|
||||
{
|
||||
SHADER shader;
|
||||
bool in_cache;
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
shader.Destroy();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
||||
|
||||
static PCacheEntry GetShaderProgram(void);
|
||||
static GLuint GetCurrentProgram(void);
|
||||
static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
|
||||
|
||||
static bool CompileShader(SHADER &shader, const char* vcode, const char* pcode);
|
||||
static GLuint CompileSingleShader(GLuint type, const char *code);
|
||||
|
||||
static void SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count);
|
||||
static void SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count);
|
||||
static void UploadConstants();
|
||||
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
static void CreateHeader(void);
|
||||
|
||||
private:
|
||||
class ProgramShaderCacheInserter : public LinearDiskCacheReader<SHADERUID, u8>
|
||||
{
|
||||
public:
|
||||
void Read(const SHADERUID &key, const u8 *value, u32 value_size);
|
||||
};
|
||||
|
||||
static PCache pshaders;
|
||||
static PCacheEntry* last_entry;
|
||||
static SHADERUID last_uid;
|
||||
|
||||
static UidChecker<PixelShaderUid,PixelShaderCode> pixel_uid_checker;
|
||||
static UidChecker<VertexShaderUid,VertexShaderCode> vertex_uid_checker;
|
||||
|
||||
static GLintptr s_vs_data_size;
|
||||
static GLintptr s_ps_data_size;
|
||||
static GLintptr s_vs_data_offset;
|
||||
static u8 *s_ubo_buffer;
|
||||
static u32 s_ubo_buffer_size;
|
||||
static bool s_ubo_dirty;
|
||||
};
|
||||
|
||||
} // namespace OGL
|
||||
#endif
|
||||
270
Source/Core/VideoBackends/OGL/Src/RasterFont.cpp
Normal file
270
Source/Core/VideoBackends/OGL/Src/RasterFont.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include "RasterFont.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
// globals
|
||||
|
||||
namespace OGL {
|
||||
|
||||
static const u32 char_width = 8;
|
||||
static const u32 char_height = 13;
|
||||
static const u32 char_offset = 32;
|
||||
static const u32 char_count = 95;
|
||||
|
||||
const u8 rasters[char_count][char_height] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
|
||||
{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}
|
||||
};
|
||||
|
||||
static const char *s_vertexShaderSrc =
|
||||
"uniform vec2 charSize;\n"
|
||||
"ATTRIN vec2 rawpos;\n"
|
||||
"ATTRIN vec2 tex0;\n"
|
||||
"VARYOUT vec2 uv0;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
" uv0 = tex0 * charSize;\n"
|
||||
"}\n";
|
||||
|
||||
static const char *s_fragmentShaderSrc =
|
||||
"uniform sampler2D samp8;\n"
|
||||
"uniform vec4 color;\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main(void) {\n"
|
||||
" ocol0 = texture(samp8,uv0) * color;\n"
|
||||
"}\n";
|
||||
|
||||
static SHADER s_shader;
|
||||
|
||||
RasterFont::RasterFont()
|
||||
{
|
||||
// generate the texture
|
||||
glGenTextures(1, &texture);
|
||||
glActiveTexture(GL_TEXTURE0+8);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
u32* texture_data = new u32[char_width*char_count*char_height];
|
||||
for(u32 y=0; y<char_height; y++) {
|
||||
for(u32 c=0; c<char_count; c++) {
|
||||
for(u32 x=0; x<char_width; x++) {
|
||||
bool pixel = rasters[c][y] & (1<<(char_width-x-1));
|
||||
texture_data[char_width*char_count*y+char_width*c+x] = pixel ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, char_width*char_count, char_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
|
||||
delete [] texture_data;
|
||||
|
||||
// generate shader
|
||||
ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc);
|
||||
|
||||
// bound uniforms
|
||||
glUniform2f(glGetUniformLocation(s_shader.glprogid,"charSize"), 1.0f / GLfloat(char_count), 1.0f);
|
||||
uniform_color_id = glGetUniformLocation(s_shader.glprogid,"color");
|
||||
glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
cached_color = -1;
|
||||
|
||||
// generate VBO & VAO
|
||||
glGenBuffers(1, &VBO);
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBindVertexArray(VAO);
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
}
|
||||
|
||||
RasterFont::~RasterFont()
|
||||
{
|
||||
glDeleteTextures(1, &texture);
|
||||
glDeleteBuffers(1, &VBO);
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
s_shader.Destroy();
|
||||
}
|
||||
|
||||
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight, u32 color)
|
||||
{
|
||||
size_t length = strlen(text);
|
||||
GLfloat *vertices = new GLfloat[length*6*4];
|
||||
|
||||
int usage = 0;
|
||||
GLfloat delta_x = GLfloat(2*char_width)/GLfloat(bbWidth);
|
||||
GLfloat delta_y = GLfloat(2*char_height)/GLfloat(bbHeight);
|
||||
GLfloat border_x = 2.0f/GLfloat(bbWidth);
|
||||
GLfloat border_y = 4.0f/GLfloat(bbHeight);
|
||||
|
||||
GLfloat x = GLfloat(start_x);
|
||||
GLfloat y = GLfloat(start_y);
|
||||
|
||||
for(size_t i=0; i<length; i++) {
|
||||
u8 c = text[i];
|
||||
|
||||
if(c == '\n') {
|
||||
x = GLfloat(start_x);
|
||||
y -= delta_y + border_y;
|
||||
continue;
|
||||
}
|
||||
|
||||
// do not print spaces, they can be skipped easily
|
||||
if(c == ' ') {
|
||||
x += delta_x + border_x;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c < char_offset || c >= char_count+char_offset) continue;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 0.0f;
|
||||
|
||||
vertices[usage++] = x+delta_x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset+1);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
vertices[usage++] = x;
|
||||
vertices[usage++] = y+delta_y;
|
||||
vertices[usage++] = GLfloat(c-char_offset);
|
||||
vertices[usage++] = 1.0f;
|
||||
|
||||
x += delta_x + border_x;
|
||||
}
|
||||
|
||||
if(!usage) {
|
||||
delete [] vertices;
|
||||
return;
|
||||
}
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, usage*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
delete [] vertices;
|
||||
|
||||
s_shader.Bind();
|
||||
|
||||
if(color != cached_color) {
|
||||
glUniform4f(uniform_color_id, GLfloat((color>>16)&0xff)/255.f,GLfloat((color>>8)&0xff)/255.f,GLfloat((color>>0)&0xff)/255.f,GLfloat((color>>24)&0xff)/255.f);
|
||||
cached_color = color;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+8);
|
||||
glDrawArrays(GL_TRIANGLES, 0, usage/4);
|
||||
}
|
||||
|
||||
}
|
||||
28
Source/Core/VideoBackends/OGL/Src/RasterFont.h
Normal file
28
Source/Core/VideoBackends/OGL/Src/RasterFont.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _RASTERFONT_H_
|
||||
#define _RASTERFONT_H_
|
||||
|
||||
namespace OGL {
|
||||
|
||||
class RasterFont {
|
||||
public:
|
||||
RasterFont();
|
||||
~RasterFont(void);
|
||||
static int debug;
|
||||
|
||||
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight, u32 color);
|
||||
private:
|
||||
|
||||
u32 VBO;
|
||||
u32 VAO;
|
||||
u32 texture;
|
||||
u32 uniform_color_id;
|
||||
u32 cached_color;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _RASTERFONT_H_
|
||||
1900
Source/Core/VideoBackends/OGL/Src/Render.cpp
Normal file
1900
Source/Core/VideoBackends/OGL/Src/Render.cpp
Normal file
File diff suppressed because it is too large
Load Diff
99
Source/Core/VideoBackends/OGL/Src/Render.h
Normal file
99
Source/Core/VideoBackends/OGL/Src/Render.h
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
#ifndef _RENDER_H_
|
||||
#define _RENDER_H_
|
||||
|
||||
#include "RenderBase.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
void ClearEFBCache();
|
||||
|
||||
enum GLSL_VERSION {
|
||||
GLSL_130,
|
||||
GLSL_140,
|
||||
GLSL_150, // and above
|
||||
GLSLES2,
|
||||
GLSLES3
|
||||
};
|
||||
|
||||
// ogl-only config, so not in VideoConfig.h
|
||||
extern struct VideoConfig {
|
||||
bool bSupportsGLSLCache;
|
||||
bool bSupportsGLPinnedMemory;
|
||||
bool bSupportsGLSync;
|
||||
bool bSupportsGLBaseVertex;
|
||||
bool bSupportCoverageMSAA;
|
||||
bool bSupportSampleShading;
|
||||
GLSL_VERSION eSupportedGLSLVersion;
|
||||
bool bSupportOGL31;
|
||||
|
||||
const char *gl_vendor;
|
||||
const char *gl_renderer;
|
||||
const char* gl_version;
|
||||
const char* glsl_version;
|
||||
|
||||
s32 max_samples;
|
||||
} g_ogl_config;
|
||||
|
||||
class Renderer : public ::Renderer
|
||||
{
|
||||
public:
|
||||
Renderer();
|
||||
~Renderer();
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void SetColorMask();
|
||||
void SetBlendMode(bool forceUpdate);
|
||||
void SetScissorRect(const TargetRectangle& rc);
|
||||
void SetGenerationMode();
|
||||
void SetDepthMode();
|
||||
void SetLogicOpMode();
|
||||
void SetDitherMode();
|
||||
void SetLineWidth();
|
||||
void SetSamplerState(int stage,int texindex);
|
||||
void SetInterlacingMode();
|
||||
|
||||
// TODO: Implement and use these
|
||||
void ApplyState(bool bUseDstAlpha) {}
|
||||
void RestoreState() {}
|
||||
|
||||
void RenderText(const char* pstr, int left, int top, u32 color);
|
||||
void DrawDebugInfo();
|
||||
void FlipImageData(u8 *data, int w, int h);
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
|
||||
|
||||
void ResetAPIState();
|
||||
void RestoreAPIState();
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc);
|
||||
|
||||
void Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc,float Gamma);
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype);
|
||||
|
||||
void UpdateViewport(Matrix44& vpCorrection);
|
||||
|
||||
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
||||
|
||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
||||
void SetPSConstant4fv(unsigned int const_number, const float *f);
|
||||
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
|
||||
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
|
||||
void SetVSConstant4fv(unsigned int const_number, const float *f);
|
||||
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
|
||||
|
||||
private:
|
||||
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
122
Source/Core/VideoBackends/OGL/Src/SamplerCache.cpp
Normal file
122
Source/Core/VideoBackends/OGL/Src/SamplerCache.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DriverDetails.h"
|
||||
#include "SamplerCache.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
SamplerCache *g_sampler_cache;
|
||||
|
||||
SamplerCache::SamplerCache()
|
||||
: m_last_max_anisotropy()
|
||||
{}
|
||||
|
||||
SamplerCache::~SamplerCache()
|
||||
{
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
Clear();
|
||||
}
|
||||
|
||||
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1)
|
||||
{
|
||||
if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
return;
|
||||
// TODO: can this go somewhere else?
|
||||
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
|
||||
{
|
||||
m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
||||
Clear();
|
||||
}
|
||||
|
||||
Params params(tm0, tm1);
|
||||
|
||||
// take equivalent forced linear when bForceFiltering
|
||||
if (g_ActiveConfig.bForceFiltering)
|
||||
{
|
||||
params.tm0.min_filter |= 0x4;
|
||||
params.tm0.mag_filter |= 0x1;
|
||||
}
|
||||
|
||||
// TODO: Should keep a circular buffer for each stage of recently used samplers.
|
||||
|
||||
auto& active_sampler = m_active_samplers[stage];
|
||||
if (active_sampler.first != params || !active_sampler.second.sampler_id)
|
||||
{
|
||||
// Active sampler does not match parameters (or is invalid), bind the proper one.
|
||||
active_sampler.first = params;
|
||||
active_sampler.second = GetEntry(params);
|
||||
glBindSampler(stage, active_sampler.second.sampler_id);
|
||||
}
|
||||
}
|
||||
|
||||
auto SamplerCache::GetEntry(const Params& params) -> Value&
|
||||
{
|
||||
auto& val = m_cache[params];
|
||||
if (!val.sampler_id)
|
||||
{
|
||||
// Sampler not found in cache, create it.
|
||||
glGenSamplers(1, &val.sampler_id);
|
||||
SetParameters(val.sampler_id, params);
|
||||
|
||||
// TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though.
|
||||
//ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size());
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void SamplerCache::SetParameters(GLuint sampler_id, const Params& params)
|
||||
{
|
||||
static const GLint min_filters[8] =
|
||||
{
|
||||
GL_NEAREST,
|
||||
GL_NEAREST_MIPMAP_NEAREST,
|
||||
GL_NEAREST_MIPMAP_LINEAR,
|
||||
GL_NEAREST,
|
||||
GL_LINEAR,
|
||||
GL_LINEAR_MIPMAP_NEAREST,
|
||||
GL_LINEAR_MIPMAP_LINEAR,
|
||||
GL_LINEAR,
|
||||
};
|
||||
|
||||
static const GLint wrap_settings[4] =
|
||||
{
|
||||
GL_CLAMP_TO_EDGE,
|
||||
GL_REPEAT,
|
||||
GL_MIRRORED_REPEAT,
|
||||
GL_REPEAT,
|
||||
};
|
||||
|
||||
auto& tm0 = params.tm0;
|
||||
auto& tm1 = params.tm1;
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filters[tm0.min_filter % ArraySize(min_filters)]);
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, tm0.mag_filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]);
|
||||
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]);
|
||||
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f);
|
||||
|
||||
#ifndef USE_GLES3
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f);
|
||||
|
||||
if (g_ActiveConfig.iMaxAnisotropy > 0)
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SamplerCache::Clear()
|
||||
{
|
||||
for (auto it = m_cache.begin(); it != m_cache.end(); ++it)
|
||||
{
|
||||
glDeleteSamplers(1, &it->second.sampler_id);
|
||||
}
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
80
Source/Core/VideoBackends/OGL/Src/SamplerCache.h
Normal file
80
Source/Core/VideoBackends/OGL/Src/SamplerCache.h
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
#ifndef INCLUDE_SAMPLER_CACHE_H_
|
||||
#define INCLUDE_SAMPLER_CACHE_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Render.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class SamplerCache : NonCopyable
|
||||
{
|
||||
public:
|
||||
SamplerCache();
|
||||
~SamplerCache();
|
||||
|
||||
void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
struct Params
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
TexMode0 tm0;
|
||||
TexMode1 tm1;
|
||||
};
|
||||
|
||||
u64 hex;
|
||||
};
|
||||
|
||||
Params()
|
||||
: hex()
|
||||
{}
|
||||
|
||||
Params(const TexMode0& _tm0, const TexMode1& _tm1)
|
||||
: tm0(_tm0)
|
||||
, tm1(_tm1)
|
||||
{
|
||||
static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int.");
|
||||
}
|
||||
|
||||
bool operator<(const Params& other) const
|
||||
{
|
||||
return hex < other.hex;
|
||||
}
|
||||
|
||||
bool operator!=(const Params& other) const
|
||||
{
|
||||
return hex != other.hex;
|
||||
}
|
||||
};
|
||||
|
||||
struct Value
|
||||
{
|
||||
Value()
|
||||
: sampler_id()
|
||||
{}
|
||||
|
||||
GLuint sampler_id;
|
||||
};
|
||||
|
||||
void SetParameters(GLuint sampler_id, const Params& params);
|
||||
Value& GetEntry(const Params& params);
|
||||
|
||||
std::map<Params, Value> m_cache;
|
||||
std::pair<Params, Value> m_active_samplers[8];
|
||||
|
||||
int m_last_max_anisotropy;
|
||||
};
|
||||
|
||||
extern SamplerCache *g_sampler_cache;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
255
Source/Core/VideoBackends/OGL/Src/StreamBuffer.cpp
Normal file
255
Source/Core/VideoBackends/OGL/Src/StreamBuffer.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Globals.h"
|
||||
#include "GLUtil.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Render.h"
|
||||
#include "DriverDetails.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static const u32 SYNC_POINTS = 16;
|
||||
static const u32 ALIGN_PINNED_MEMORY = 4096;
|
||||
|
||||
StreamBuffer::StreamBuffer(u32 type, size_t size, StreamType uploadType)
|
||||
: m_uploadtype(uploadType), m_buffertype(type), m_size(size)
|
||||
{
|
||||
glGenBuffers(1, &m_buffer);
|
||||
|
||||
bool nvidia = !strcmp(g_ogl_config.gl_vendor, "NVIDIA Corporation");
|
||||
|
||||
if(m_uploadtype & STREAM_DETECT)
|
||||
{
|
||||
// TODO: move this to InitBackendInfo
|
||||
if(g_ActiveConfig.bHackedBufferUpload && DriverDetails::HasBug(DriverDetails::BUG_BROKENHACKEDBUFFER))
|
||||
{
|
||||
OSD::AddMessage("Vertex Streaming Hack isn't supported by your GPU.", 10000);
|
||||
g_ActiveConfig.bHackedBufferUpload = false;
|
||||
g_Config.bHackedBufferUpload = false;
|
||||
}
|
||||
|
||||
if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERDATA)
|
||||
&& !DriverDetails::HasBug(DriverDetails::BUG_ISPOWERVR)
|
||||
&& !DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
m_uploadtype = BUFFERDATA;
|
||||
else if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERSUBDATA))
|
||||
m_uploadtype = BUFFERSUBDATA;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ActiveConfig.bHackedBufferUpload && (m_uploadtype & MAP_AND_RISK))
|
||||
m_uploadtype = MAP_AND_RISK;
|
||||
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && (!DriverDetails::HasBug(DriverDetails::BUG_BROKENPINNEDMEMORY) || type != GL_ELEMENT_ARRAY_BUFFER) && (m_uploadtype & PINNED_MEMORY))
|
||||
m_uploadtype = PINNED_MEMORY;
|
||||
else if(nvidia && (m_uploadtype & BUFFERSUBDATA))
|
||||
m_uploadtype = BUFFERSUBDATA;
|
||||
else if(g_ogl_config.bSupportsGLSync && (m_uploadtype & MAP_AND_SYNC))
|
||||
m_uploadtype = MAP_AND_SYNC;
|
||||
else
|
||||
m_uploadtype = MAP_AND_ORPHAN;
|
||||
}
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
StreamBuffer::~StreamBuffer()
|
||||
{
|
||||
Shutdown();
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
#define SLOT(x) (x)*SYNC_POINTS/m_size
|
||||
|
||||
void StreamBuffer::Alloc ( size_t size, u32 stride )
|
||||
{
|
||||
size_t m_iterator_aligned = m_iterator;
|
||||
if(m_iterator_aligned && stride) {
|
||||
m_iterator_aligned--;
|
||||
m_iterator_aligned = m_iterator_aligned - (m_iterator_aligned % stride) + stride;
|
||||
}
|
||||
size_t iter_end = m_iterator_aligned + size;
|
||||
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_ORPHAN:
|
||||
if(iter_end >= m_size) {
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
m_iterator_aligned = 0;
|
||||
}
|
||||
break;
|
||||
case MAP_AND_SYNC:
|
||||
case PINNED_MEMORY:
|
||||
|
||||
// insert waiting slots for used memory
|
||||
for(u32 i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
|
||||
{
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
m_used_iterator = m_iterator;
|
||||
|
||||
// wait for new slots to end of buffer
|
||||
for(u32 i=SLOT(m_free_iterator)+1; i<=SLOT(iter_end) && i < SYNC_POINTS; i++)
|
||||
{
|
||||
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fences[i]);
|
||||
}
|
||||
m_free_iterator = iter_end;
|
||||
|
||||
// if buffer is full
|
||||
if(iter_end >= m_size) {
|
||||
|
||||
// insert waiting slots in unused space at the end of the buffer
|
||||
for(u32 i=SLOT(m_used_iterator); i < SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
// move to the start
|
||||
m_used_iterator = m_iterator_aligned = m_iterator = 0; // offset 0 is always aligned
|
||||
iter_end = size;
|
||||
|
||||
// wait for space at the start
|
||||
for(u32 i=0; i<=SLOT(iter_end); i++)
|
||||
{
|
||||
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
glDeleteSync(fences[i]);
|
||||
}
|
||||
m_free_iterator = iter_end;
|
||||
}
|
||||
|
||||
break;
|
||||
case MAP_AND_RISK:
|
||||
if(iter_end >= m_size) {
|
||||
m_iterator_aligned = 0;
|
||||
}
|
||||
break;
|
||||
case BUFFERSUBDATA:
|
||||
case BUFFERDATA:
|
||||
m_iterator_aligned = 0;
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
m_iterator = m_iterator_aligned;
|
||||
}
|
||||
|
||||
size_t StreamBuffer::Upload ( u8* data, size_t size )
|
||||
{
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
case MAP_AND_ORPHAN:
|
||||
pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
if(pointer) {
|
||||
memcpy(pointer, data, size);
|
||||
glUnmapBuffer(m_buffertype);
|
||||
} else {
|
||||
ERROR_LOG(VIDEO, "Buffer mapping failed");
|
||||
}
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
case MAP_AND_RISK:
|
||||
if(pointer)
|
||||
memcpy(pointer+m_iterator, data, size);
|
||||
break;
|
||||
case BUFFERSUBDATA:
|
||||
glBufferSubData(m_buffertype, m_iterator, size, data);
|
||||
break;
|
||||
case BUFFERDATA:
|
||||
glBufferData(m_buffertype, size, data, GL_STREAM_DRAW);
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
size_t ret = m_iterator;
|
||||
m_iterator += size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void StreamBuffer::Init()
|
||||
{
|
||||
m_iterator = 0;
|
||||
m_used_iterator = 0;
|
||||
m_free_iterator = 0;
|
||||
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
fences = new GLsync[SYNC_POINTS];
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
case MAP_AND_ORPHAN:
|
||||
case BUFFERSUBDATA:
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
glGetError(); // errors before this allocation should be ignored
|
||||
fences = new GLsync[SYNC_POINTS];
|
||||
for(u32 i=0; i<SYNC_POINTS; i++)
|
||||
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
pointer = (u8*)AllocateAlignedMemory(ROUND_UP(m_size,ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY );
|
||||
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer);
|
||||
glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size,ALIGN_PINNED_MEMORY), pointer, GL_STREAM_COPY);
|
||||
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
|
||||
// on error, switch to another backend. some old catalyst seems to have broken pinned memory support
|
||||
if(glGetError() != GL_NO_ERROR) {
|
||||
ERROR_LOG(VIDEO, "Pinned memory detected, but not working. Please report this: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version);
|
||||
Shutdown();
|
||||
m_uploadtype = MAP_AND_SYNC;
|
||||
Init();
|
||||
}
|
||||
break;
|
||||
case MAP_AND_RISK:
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
|
||||
pointer = (u8*)glMapBufferRange(m_buffertype, 0, m_size, GL_MAP_WRITE_BIT);
|
||||
glUnmapBuffer(m_buffertype);
|
||||
if(!pointer)
|
||||
ERROR_LOG(VIDEO, "Buffer allocation failed");
|
||||
break;
|
||||
case BUFFERDATA:
|
||||
glBindBuffer(m_buffertype, m_buffer);
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void StreamBuffer::Shutdown()
|
||||
{
|
||||
switch(m_uploadtype) {
|
||||
case MAP_AND_SYNC:
|
||||
DeleteFences();
|
||||
break;
|
||||
case MAP_AND_RISK:
|
||||
case MAP_AND_ORPHAN:
|
||||
case BUFFERSUBDATA:
|
||||
case BUFFERDATA:
|
||||
break;
|
||||
case PINNED_MEMORY:
|
||||
DeleteFences();
|
||||
glBindBuffer(m_buffertype, 0);
|
||||
glFinish(); // ogl pipeline must be flushed, else this buffer can be in use
|
||||
FreeAlignedMemory(pointer);
|
||||
break;
|
||||
case STREAM_DETECT:
|
||||
case DETECT_MASK: // Just to shutup warnings
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void StreamBuffer::DeleteFences()
|
||||
{
|
||||
for(u32 i=SLOT(m_free_iterator)+1; i < SYNC_POINTS; i++)
|
||||
glDeleteSync(fences[i]);
|
||||
for(u32 i=0; i<SLOT(m_iterator); i++)
|
||||
glDeleteSync(fences[i]);
|
||||
delete [] fences;
|
||||
}
|
||||
|
||||
}
|
||||
60
Source/Core/VideoBackends/OGL/Src/StreamBuffer.h
Normal file
60
Source/Core/VideoBackends/OGL/Src/StreamBuffer.h
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef STREAMBUFFER_H
|
||||
#define STREAMBUFFER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
// glew < 1.8 doesn't support pinned memory
|
||||
#ifndef GLEW_AMD_pinned_memory
|
||||
#define GLEW_AMD_pinned_memory glewIsSupported("GL_AMD_pinned_memory")
|
||||
#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
|
||||
#endif
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
enum StreamType {
|
||||
DETECT_MASK = 0x7F,
|
||||
STREAM_DETECT = (1 << 0),
|
||||
MAP_AND_ORPHAN = (1 << 1),
|
||||
MAP_AND_SYNC = (1 << 2),
|
||||
MAP_AND_RISK = (1 << 3),
|
||||
PINNED_MEMORY = (1 << 4),
|
||||
BUFFERSUBDATA = (1 << 5),
|
||||
BUFFERDATA = (1 << 6)
|
||||
};
|
||||
|
||||
class StreamBuffer {
|
||||
|
||||
public:
|
||||
StreamBuffer(u32 type, size_t size, StreamType uploadType = DETECT_MASK);
|
||||
~StreamBuffer();
|
||||
|
||||
void Alloc(size_t size, u32 stride = 0);
|
||||
size_t Upload(u8 *data, size_t size);
|
||||
|
||||
u32 getBuffer() { return m_buffer; }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void DeleteFences();
|
||||
|
||||
StreamType m_uploadtype;
|
||||
u32 m_buffer;
|
||||
u32 m_buffertype;
|
||||
size_t m_size;
|
||||
u8 *pointer;
|
||||
size_t m_iterator;
|
||||
size_t m_used_iterator;
|
||||
size_t m_free_iterator;
|
||||
GLsync *fences;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STREAMBUFFER_H
|
||||
490
Source/Core/VideoBackends/OGL/Src/TextureCache.cpp
Normal file
490
Source/Core/VideoBackends/OGL/Src/TextureCache.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#ifdef _WIN32
|
||||
#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
|
||||
#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
|
||||
#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
|
||||
#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
|
||||
#include <intrin.h>
|
||||
#undef _interlockedbittestandset
|
||||
#undef _interlockedbittestandreset
|
||||
#undef _interlockedbittestandset64
|
||||
#undef _interlockedbittestandreset64
|
||||
#endif
|
||||
|
||||
#include "BPStructs.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "FileUtil.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "Globals.h"
|
||||
#include "Hash.h"
|
||||
#include "HiresTextures.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "Render.h"
|
||||
#include "Statistics.h"
|
||||
#include "StringUtil.h"
|
||||
#include "TextureCache.h"
|
||||
#include "TextureConverter.h"
|
||||
#include "TextureDecoder.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
static SHADER s_ColorMatrixProgram;
|
||||
static SHADER s_DepthMatrixProgram;
|
||||
static GLuint s_ColorMatrixUniform;
|
||||
static GLuint s_DepthMatrixUniform;
|
||||
static u32 s_ColorCbufid;
|
||||
static u32 s_DepthCbufid;
|
||||
|
||||
static u32 s_Textures[8];
|
||||
static u32 s_ActiveTexture;
|
||||
static u32 s_NextStage;
|
||||
|
||||
struct VBOCache {
|
||||
GLuint vbo;
|
||||
GLuint vao;
|
||||
TargetRectangle targetSource;
|
||||
};
|
||||
static std::map<u64,VBOCache> s_VBO;
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
|
||||
{
|
||||
#ifndef USE_GLES3
|
||||
int width = std::max(virtual_width >> level, 1);
|
||||
int height = std::max(virtual_height >> level, 1);
|
||||
std::vector<u32> data(width * height);
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(textarget, tex);
|
||||
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
|
||||
glBindTexture(textarget, 0);
|
||||
TextureCache::SetStage();
|
||||
|
||||
const GLenum err = GL_REPORT_ERROR();
|
||||
if (GL_NO_ERROR != err)
|
||||
{
|
||||
PanicAlert("Can't save texture, GL Error: %s", gluErrorString(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
return SaveTGA(filename, width, height, &data[0]);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntry::~TCacheEntry()
|
||||
{
|
||||
if (texture)
|
||||
{
|
||||
for(int i=0; i<8; i++)
|
||||
if(s_Textures[i] == texture)
|
||||
s_Textures[i] = 0;
|
||||
glDeleteTextures(1, &texture);
|
||||
texture = 0;
|
||||
}
|
||||
|
||||
if (framebuffer)
|
||||
{
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
framebuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntry::TCacheEntry()
|
||||
{
|
||||
glGenTextures(1, &texture);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
framebuffer = 0;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||
{
|
||||
if (s_Textures[stage] != texture)
|
||||
{
|
||||
if (s_ActiveTexture != stage)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + stage);
|
||||
s_ActiveTexture = stage;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
s_Textures[stage] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
|
||||
{
|
||||
// TODO: make ogl dump PNGs
|
||||
std::string tga_filename(filename);
|
||||
tga_filename.replace(tga_filename.size() - 3, 3, "tga");
|
||||
|
||||
return SaveTexture(tga_filename.c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, level);
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
|
||||
unsigned int height, unsigned int expanded_width,
|
||||
unsigned int tex_levels, PC_TexFormat pcfmt)
|
||||
{
|
||||
int gl_format = 0,
|
||||
gl_iformat = 0,
|
||||
gl_type = 0;
|
||||
|
||||
if (pcfmt != PC_TEX_FMT_DXT1)
|
||||
{
|
||||
switch (pcfmt)
|
||||
{
|
||||
default:
|
||||
case PC_TEX_FMT_NONE:
|
||||
PanicAlert("Invalid PC texture format %i", pcfmt);
|
||||
case PC_TEX_FMT_BGRA32:
|
||||
gl_format = GL_BGRA;
|
||||
gl_iformat = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case PC_TEX_FMT_RGBA32:
|
||||
gl_format = GL_RGBA;
|
||||
gl_iformat = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
#ifndef USE_GLES3
|
||||
case PC_TEX_FMT_I4_AS_I8:
|
||||
gl_format = GL_LUMINANCE;
|
||||
gl_iformat = GL_INTENSITY4;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case PC_TEX_FMT_IA4_AS_IA8:
|
||||
gl_format = GL_LUMINANCE_ALPHA;
|
||||
gl_iformat = GL_LUMINANCE4_ALPHA4;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case PC_TEX_FMT_I8:
|
||||
gl_format = GL_LUMINANCE;
|
||||
gl_iformat = GL_INTENSITY8;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case PC_TEX_FMT_IA8:
|
||||
gl_format = GL_LUMINANCE_ALPHA;
|
||||
gl_iformat = GL_LUMINANCE8_ALPHA8;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
#endif
|
||||
case PC_TEX_FMT_RGB565:
|
||||
gl_format = GL_RGB;
|
||||
gl_iformat = GL_RGB;
|
||||
gl_type = GL_UNSIGNED_SHORT_5_6_5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TCacheEntry &entry = *new TCacheEntry;
|
||||
entry.gl_format = gl_format;
|
||||
entry.gl_iformat = gl_iformat;
|
||||
entry.gl_type = gl_type;
|
||||
entry.pcfmt = pcfmt;
|
||||
|
||||
entry.m_tex_levels = tex_levels;
|
||||
|
||||
entry.Load(width, height, expanded_width, 0);
|
||||
|
||||
return &entry;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level)
|
||||
{
|
||||
if (s_ActiveTexture != s_NextStage)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + s_NextStage);
|
||||
s_ActiveTexture = s_NextStage;
|
||||
}
|
||||
|
||||
if (s_Textures[s_NextStage] != texture)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
s_Textures[s_NextStage] = texture;
|
||||
}
|
||||
|
||||
// TODO: sloppy, just do this on creation?
|
||||
if (level == 0)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m_tex_levels - 1);
|
||||
}
|
||||
|
||||
if (pcfmt != PC_TEX_FMT_DXT1)
|
||||
{
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
|
||||
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("PC_TEX_FMT_DXT1 support disabled");
|
||||
//glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
||||
//width, height, 0, expanded_width * expanded_height/2, temp);
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
|
||||
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
|
||||
{
|
||||
TCacheEntry *const entry = new TCacheEntry;
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(GL_TEXTURE_2D, entry->texture);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
const GLenum
|
||||
gl_format = GL_RGBA,
|
||||
gl_iformat = GL_RGBA,
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
entry->m_tex_levels = 1;
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_h, 0, gl_format, gl_type, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenFramebuffers(1, &entry->framebuffer);
|
||||
FramebufferManager::SetFramebuffer(entry->framebuffer);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, entry->texture, 0);
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
SetStage();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat)
|
||||
{
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// Make sure to resolve anything we need to read from.
|
||||
const GLuint read_texture = (srcFormat == PIXELFMT_Z24) ?
|
||||
FramebufferManager::ResolveAndGetDepthTarget(srcRect) :
|
||||
FramebufferManager::ResolveAndGetRenderTarget(srcRect);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
FramebufferManager::SetFramebuffer(framebuffer);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(getFbType(), read_texture);
|
||||
|
||||
glViewport(0, 0, virtual_width, virtual_height);
|
||||
|
||||
if(srcFormat == PIXELFMT_Z24) {
|
||||
s_DepthMatrixProgram.Bind();
|
||||
if(s_DepthCbufid != cbufid)
|
||||
glUniform4fv(s_DepthMatrixUniform, 5, colmat);
|
||||
s_DepthCbufid = cbufid;
|
||||
} else {
|
||||
s_ColorMatrixProgram.Bind();
|
||||
if(s_ColorCbufid != cbufid)
|
||||
glUniform4fv(s_ColorMatrixUniform, 7, colmat);
|
||||
s_ColorCbufid = cbufid;
|
||||
}
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// should be unique enough, if not, vbo will "only" be uploaded to much
|
||||
u64 targetSourceHash = u64(targetSource.left)<<48 | u64(targetSource.top)<<32 | u64(targetSource.right)<<16 | u64(targetSource.bottom);
|
||||
std::map<u64, VBOCache>::iterator vbo_it = s_VBO.find(targetSourceHash);
|
||||
|
||||
if(vbo_it == s_VBO.end()) {
|
||||
VBOCache item;
|
||||
item.targetSource.bottom = -1;
|
||||
item.targetSource.top = -1;
|
||||
item.targetSource.left = -1;
|
||||
item.targetSource.right = -1;
|
||||
glGenBuffers(1, &item.vbo);
|
||||
glGenVertexArrays(1, &item.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, item.vbo);
|
||||
glBindVertexArray(item.vao);
|
||||
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
vbo_it = s_VBO.insert(std::pair<u64,VBOCache>(targetSourceHash, item)).first;
|
||||
}
|
||||
if(!(vbo_it->second.targetSource == targetSource)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, 1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.bottom,
|
||||
-1.f, -1.f,
|
||||
(GLfloat)targetSource.left, (GLfloat)targetSource.top,
|
||||
1.f, 1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.bottom,
|
||||
1.f, -1.f,
|
||||
(GLfloat)targetSource.right, (GLfloat)targetSource.top
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo_it->second.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
vbo_it->second.targetSource = targetSource;
|
||||
}
|
||||
|
||||
glBindVertexArray(vbo_it->second.vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
if (false == g_ActiveConfig.bCopyEFBToTexture)
|
||||
{
|
||||
int encoded_size = TextureConverter::EncodeToRamFromTexture(
|
||||
addr,
|
||||
read_texture,
|
||||
srcFormat == PIXELFMT_Z24,
|
||||
isIntensity,
|
||||
dstFormat,
|
||||
scaleByHalf,
|
||||
srcRect);
|
||||
|
||||
u8* dst = Memory::GetPointer(addr);
|
||||
u64 const new_hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
|
||||
|
||||
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
|
||||
if (!g_ActiveConfig.bEFBCopyCacheEnable)
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
else if (!TextureCache::Find(addr, new_hash))
|
||||
TextureCache::MakeRangeDynamic(addr,encoded_size);
|
||||
|
||||
hash = new_hash;
|
||||
}
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if (g_ActiveConfig.bDumpEFBTarget)
|
||||
{
|
||||
static int count = 0;
|
||||
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
|
||||
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
|
||||
}
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
TextureCache::TextureCache()
|
||||
{
|
||||
const char *pColorMatrixProg =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"uniform vec4 colmat[7];\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"\n"
|
||||
"void main(){\n"
|
||||
" vec4 texcol = texture2DRect(samp9, uv0);\n"
|
||||
" texcol = round(texcol * colmat[5]) * colmat[6];\n"
|
||||
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n"
|
||||
"}\n";
|
||||
|
||||
const char *pDepthMatrixProg =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"uniform vec4 colmat[5];\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"\n"
|
||||
"void main(){\n"
|
||||
" vec4 texcol = texture2DRect(samp9, uv0);\n"
|
||||
" vec4 EncodedDepth = fract((texcol.r * (16777215.0/16777216.0)) * vec4(1.0,256.0,256.0*256.0,1.0));\n"
|
||||
" texcol = round(EncodedDepth * (16777216.0/16777215.0) * vec4(255.0,255.0,255.0,15.0)) / vec4(255.0,255.0,255.0,15.0);\n"
|
||||
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];"
|
||||
"}\n";
|
||||
|
||||
const char *VProgram =
|
||||
"ATTRIN vec2 rawpos;\n"
|
||||
"ATTRIN vec2 tex0;\n"
|
||||
"VARYOUT vec2 uv0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" uv0 = tex0;\n"
|
||||
" gl_Position = vec4(rawpos,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, VProgram, pColorMatrixProg);
|
||||
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, VProgram, pDepthMatrixProg);
|
||||
|
||||
s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat");
|
||||
s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat");
|
||||
s_ColorCbufid = -1;
|
||||
s_DepthCbufid = -1;
|
||||
|
||||
s_ActiveTexture = -1;
|
||||
s_NextStage = -1;
|
||||
for(int i=0; i<8; i++)
|
||||
s_Textures[i] = -1;
|
||||
}
|
||||
|
||||
|
||||
TextureCache::~TextureCache()
|
||||
{
|
||||
s_ColorMatrixProgram.Destroy();
|
||||
s_DepthMatrixProgram.Destroy();
|
||||
|
||||
for(std::map<u64, VBOCache>::iterator it = s_VBO.begin(); it != s_VBO.end(); it++) {
|
||||
glDeleteBuffers(1, &it->second.vbo);
|
||||
glDeleteVertexArrays(1, &it->second.vao);
|
||||
}
|
||||
s_VBO.clear();
|
||||
}
|
||||
|
||||
void TextureCache::DisableStage(unsigned int stage)
|
||||
{
|
||||
}
|
||||
|
||||
void TextureCache::SetStage ()
|
||||
{
|
||||
// -1 is the initial value as we don't know which testure should be bound
|
||||
if(s_ActiveTexture != (u32)-1)
|
||||
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
|
||||
}
|
||||
|
||||
void TextureCache::SetNextStage ( unsigned int stage )
|
||||
{
|
||||
s_NextStage = stage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
71
Source/Core/VideoBackends/OGL/Src/TextureCache.h
Normal file
71
Source/Core/VideoBackends/OGL/Src/TextureCache.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TEXTUREMNGR_H_
|
||||
#define _TEXTUREMNGR_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "GLUtil.h"
|
||||
#include "BPStructs.h"
|
||||
|
||||
#include "TextureCacheBase.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class TextureCache : public ::TextureCache
|
||||
{
|
||||
public:
|
||||
TextureCache();
|
||||
static void DisableStage(unsigned int stage);
|
||||
static void SetStage();
|
||||
static void SetNextStage(unsigned int stage);
|
||||
|
||||
private:
|
||||
struct TCacheEntry : TCacheEntryBase
|
||||
{
|
||||
GLuint texture;
|
||||
GLuint framebuffer;
|
||||
|
||||
PC_TexFormat pcfmt;
|
||||
|
||||
int gl_format;
|
||||
int gl_iformat;
|
||||
int gl_type;
|
||||
|
||||
int m_tex_levels;
|
||||
|
||||
//TexMode0 mode; // current filter and clamp modes that texture is set to
|
||||
//TexMode1 mode1; // current filter and clamp modes that texture is set to
|
||||
|
||||
TCacheEntry();
|
||||
~TCacheEntry();
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level);
|
||||
|
||||
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
unsigned int srcFormat, const EFBRectangle& srcRect,
|
||||
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
|
||||
const float *colmat);
|
||||
|
||||
void Bind(unsigned int stage);
|
||||
bool Save(const char filename[], unsigned int level);
|
||||
};
|
||||
|
||||
~TextureCache();
|
||||
|
||||
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
|
||||
|
||||
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h);
|
||||
};
|
||||
|
||||
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level);
|
||||
|
||||
}
|
||||
|
||||
#endif // _TEXTUREMNGR_H_
|
||||
440
Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp
Normal file
440
Source/Core/VideoBackends/OGL/Src/TextureConverter.cpp
Normal file
@@ -0,0 +1,440 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Fast image conversion using OpenGL shaders.
|
||||
// This kind of stuff would be a LOT nicer with OpenCL.
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "TextureConverter.h"
|
||||
#include "TextureConversionShader.h"
|
||||
#include "TextureCache.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "Globals.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "Render.h"
|
||||
#include "FileUtil.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
namespace TextureConverter
|
||||
{
|
||||
|
||||
using OGL::TextureCache;
|
||||
|
||||
static GLuint s_texConvFrameBuffer = 0;
|
||||
static GLuint s_srcTexture = 0; // for decoding from RAM
|
||||
static GLuint s_srcTextureWidth = 0;
|
||||
static GLuint s_srcTextureHeight = 0;
|
||||
static GLuint s_dstTexture = 0; // for encoding to RAM
|
||||
|
||||
const int renderBufferWidth = 1024;
|
||||
const int renderBufferHeight = 1024;
|
||||
|
||||
static SHADER s_rgbToYuyvProgram;
|
||||
static SHADER s_yuyvToRgbProgram;
|
||||
|
||||
// Not all slots are taken - but who cares.
|
||||
const u32 NUM_ENCODING_PROGRAMS = 64;
|
||||
static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
|
||||
|
||||
static GLuint s_encode_VBO = 0;
|
||||
static GLuint s_encode_VAO = 0;
|
||||
static GLuint s_decode_VBO = 0;
|
||||
static GLuint s_decode_VAO = 0;
|
||||
static TargetRectangle s_cached_sourceRc;
|
||||
static int s_cached_srcWidth = 0;
|
||||
static int s_cached_srcHeight = 0;
|
||||
|
||||
static const char *VProgram =
|
||||
"ATTRIN vec2 rawpos;\n"
|
||||
"ATTRIN vec2 tex0;\n"
|
||||
"VARYOUT vec2 uv0;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" uv0 = tex0;\n"
|
||||
" gl_Position = vec4(rawpos, 0.0, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
void CreatePrograms()
|
||||
{
|
||||
// Output is BGRA because that is slightly faster than RGBA.
|
||||
const char *FProgramRgbToYuyv =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec3 c0 = texture2DRect(samp9, uv0).rgb;\n"
|
||||
" vec3 c1 = texture2DRect(samp9, uv0 + vec2(1.0, 0.0)).rgb;\n"
|
||||
" vec3 c01 = (c0 + c1) * 0.5;\n"
|
||||
" vec3 y_const = vec3(0.257,0.504,0.098);\n"
|
||||
" vec3 u_const = vec3(-0.148,-0.291,0.439);\n"
|
||||
" vec3 v_const = vec3(0.439,-0.368,-0.071);\n"
|
||||
" vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);\n"
|
||||
" ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n"
|
||||
"}\n";
|
||||
|
||||
const char *FProgramYuyvToRgb =
|
||||
"uniform sampler2DRect samp9;\n"
|
||||
"VARYIN vec2 uv0;\n"
|
||||
"COLOROUT(ocol0)\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 c0 = texture2DRect(samp9, uv0).rgba;\n"
|
||||
" float f = step(0.5, fract(uv0.x));\n"
|
||||
" float y = mix(c0.b, c0.r, f);\n"
|
||||
" float yComp = 1.164 * (y - 0.0625);\n"
|
||||
" float uComp = c0.g - 0.5;\n"
|
||||
" float vComp = c0.a - 0.5;\n"
|
||||
" ocol0 = vec4(yComp + (1.596 * vComp),\n"
|
||||
" yComp - (0.813 * vComp) - (0.391 * uComp),\n"
|
||||
" yComp + (2.018 * uComp),\n"
|
||||
" 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgram, FProgramRgbToYuyv);
|
||||
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgram, FProgramYuyvToRgb);
|
||||
}
|
||||
|
||||
SHADER &GetOrCreateEncodingShader(u32 format)
|
||||
{
|
||||
if (format > NUM_ENCODING_PROGRAMS)
|
||||
{
|
||||
PanicAlert("Unknown texture copy format: 0x%x\n", format);
|
||||
return s_encodingPrograms[0];
|
||||
}
|
||||
|
||||
if (s_encodingPrograms[format].glprogid == 0)
|
||||
{
|
||||
const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_OPENGL);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
|
||||
{
|
||||
static int counter = 0;
|
||||
char szTemp[MAX_PATH];
|
||||
sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
|
||||
|
||||
SaveData(szTemp, shader);
|
||||
}
|
||||
#endif
|
||||
|
||||
ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader);
|
||||
}
|
||||
return s_encodingPrograms[format];
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
glGenFramebuffers(1, &s_texConvFrameBuffer);
|
||||
|
||||
glGenBuffers(1, &s_encode_VBO );
|
||||
glGenVertexArrays(1, &s_encode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
s_cached_sourceRc.top = -1;
|
||||
s_cached_sourceRc.bottom = -1;
|
||||
s_cached_sourceRc.left = -1;
|
||||
s_cached_sourceRc.right = -1;
|
||||
|
||||
glGenBuffers(1, &s_decode_VBO );
|
||||
glGenVertexArrays(1, &s_decode_VAO );
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
s_cached_srcWidth = -1;
|
||||
s_cached_srcHeight = -1;
|
||||
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
|
||||
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
|
||||
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
|
||||
|
||||
s_srcTextureWidth = 0;
|
||||
s_srcTextureHeight = 0;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 9);
|
||||
glGenTextures(1, &s_srcTexture);
|
||||
glBindTexture(getFbType(), s_srcTexture);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
glGenTextures(1, &s_dstTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, s_dstTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
CreatePrograms();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
glDeleteTextures(1, &s_srcTexture);
|
||||
glDeleteTextures(1, &s_dstTexture);
|
||||
glDeleteFramebuffers(1, &s_texConvFrameBuffer);
|
||||
glDeleteBuffers(1, &s_encode_VBO );
|
||||
glDeleteVertexArrays(1, &s_encode_VAO );
|
||||
glDeleteBuffers(1, &s_decode_VBO );
|
||||
glDeleteVertexArrays(1, &s_decode_VAO );
|
||||
|
||||
s_rgbToYuyvProgram.Destroy();
|
||||
s_yuyvToRgbProgram.Destroy();
|
||||
|
||||
for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++)
|
||||
s_encodingPrograms[i].Destroy();
|
||||
|
||||
s_srcTexture = 0;
|
||||
s_dstTexture = 0;
|
||||
s_texConvFrameBuffer = 0;
|
||||
}
|
||||
|
||||
void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight, int readStride,
|
||||
bool toTexture, bool linearFilter)
|
||||
{
|
||||
|
||||
|
||||
// switch to texture converter frame buffer
|
||||
// attach render buffer as color destination
|
||||
FramebufferManager::SetFramebuffer(s_texConvFrameBuffer);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_dstTexture, 0);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// set source texture
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(getFbType(), srcTexture);
|
||||
|
||||
if (linearFilter)
|
||||
{
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(getFbType(), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
if(!(s_cached_sourceRc == sourceRc)) {
|
||||
GLfloat vertices[] = {
|
||||
-1.f, -1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.top,
|
||||
-1.f, 1.f,
|
||||
(float)sourceRc.left, (float)sourceRc.bottom,
|
||||
1.f, -1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.top,
|
||||
1.f, 1.f,
|
||||
(float)sourceRc.right, (float)sourceRc.bottom
|
||||
};
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
|
||||
|
||||
s_cached_sourceRc = sourceRc;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_encode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// .. and then read back the results.
|
||||
// TODO: make this less slow.
|
||||
|
||||
int writeStride = bpmem.copyMipMapStrideChannels * 32;
|
||||
|
||||
if (writeStride != readStride && toTexture)
|
||||
{
|
||||
// writing to a texture of a different size
|
||||
|
||||
int readHeight = readStride / dstWidth;
|
||||
readHeight /= 4; // 4 bytes per pixel
|
||||
|
||||
int readStart = 0;
|
||||
int readLoops = dstHeight / readHeight;
|
||||
for (int i = 0; i < readLoops; i++)
|
||||
{
|
||||
glReadPixels(0, readStart, (GLsizei)dstWidth, (GLsizei)readHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
|
||||
readStart += readHeight;
|
||||
destAddr += writeStride;
|
||||
}
|
||||
}
|
||||
else
|
||||
glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
}
|
||||
|
||||
int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source)
|
||||
{
|
||||
u32 format = copyfmt;
|
||||
|
||||
if (bFromZBuffer)
|
||||
{
|
||||
format |= _GX_TF_ZTF;
|
||||
if (copyfmt == 11)
|
||||
format = GX_TF_Z16;
|
||||
else if (format < GX_TF_Z8 || format > GX_TF_Z24X8)
|
||||
format |= _GX_TF_CTF;
|
||||
}
|
||||
else
|
||||
if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt))
|
||||
format |= _GX_TF_CTF;
|
||||
|
||||
SHADER& texconv_shader = GetOrCreateEncodingShader(format);
|
||||
|
||||
u8 *dest_ptr = Memory::GetPointer(address);
|
||||
|
||||
int width = (source.right - source.left) >> bScaleByHalf;
|
||||
int height = (source.bottom - source.top) >> bScaleByHalf;
|
||||
|
||||
int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format);
|
||||
|
||||
u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1;
|
||||
u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1;
|
||||
u16 samples = TextureConversionShader::GetEncodedSampleCount(format);
|
||||
|
||||
// only copy on cache line boundaries
|
||||
// extra pixels are copied but not displayed in the resulting texture
|
||||
s32 expandedWidth = (width + blkW) & (~blkW);
|
||||
s32 expandedHeight = (height + blkH) & (~blkH);
|
||||
|
||||
float sampleStride = bScaleByHalf ? 2.f : 1.f;
|
||||
|
||||
float params[] = {
|
||||
Renderer::EFBToScaledXf(sampleStride), Renderer::EFBToScaledYf(sampleStride),
|
||||
0.0f, 0.0f,
|
||||
(float)expandedWidth, (float)Renderer::EFBToScaledY(expandedHeight)-1,
|
||||
(float)Renderer::EFBToScaledX(source.left), (float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight)
|
||||
};
|
||||
|
||||
texconv_shader.Bind();
|
||||
glUniform4fv(texconv_shader.UniformLocations[C_COLORS], 2, params);
|
||||
|
||||
TargetRectangle scaledSource;
|
||||
scaledSource.top = 0;
|
||||
scaledSource.bottom = expandedHeight;
|
||||
scaledSource.left = 0;
|
||||
scaledSource.right = expandedWidth / samples;
|
||||
int cacheBytes = 32;
|
||||
if ((format & 0x0f) == 6)
|
||||
cacheBytes = 64;
|
||||
|
||||
int readStride = (expandedWidth * cacheBytes) /
|
||||
TexDecoder_GetBlockWidthInTexels(format);
|
||||
EncodeToRamUsingShader(source_texture, scaledSource,
|
||||
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
|
||||
true, bScaleByHalf > 0 && !bFromZBuffer);
|
||||
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
|
||||
|
||||
}
|
||||
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight)
|
||||
{
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
s_rgbToYuyvProgram.Bind();
|
||||
|
||||
EncodeToRamUsingShader(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
TextureCache::DisableStage(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
|
||||
// Should be scale free.
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture)
|
||||
{
|
||||
u8* srcAddr = Memory::GetPointer(xfbAddr);
|
||||
if (!srcAddr)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Tried to decode from invalid memory address");
|
||||
return;
|
||||
}
|
||||
|
||||
int srcFmtWidth = srcWidth / 2;
|
||||
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
// switch to texture converter frame buffer
|
||||
// attach destTexture as color destination
|
||||
FramebufferManager::SetFramebuffer(s_texConvFrameBuffer);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destTexture, 0);
|
||||
|
||||
GL_REPORT_FBO_ERROR();
|
||||
|
||||
// activate source texture
|
||||
// set srcAddr as data for source texture
|
||||
glActiveTexture(GL_TEXTURE0+9);
|
||||
glBindTexture(getFbType(), s_srcTexture);
|
||||
|
||||
// TODO: make this less slow. (How?)
|
||||
if ((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
|
||||
{
|
||||
glTexSubImage2D(getFbType(), 0,0,0,s_srcTextureWidth, s_srcTextureHeight,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(getFbType(), 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight,
|
||||
0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
|
||||
s_srcTextureWidth = (GLsizei)srcFmtWidth;
|
||||
s_srcTextureHeight = (GLsizei)srcHeight;
|
||||
}
|
||||
|
||||
glViewport(0, 0, srcWidth, srcHeight);
|
||||
s_yuyvToRgbProgram.Bind();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
if(s_cached_srcHeight != srcHeight || s_cached_srcWidth != srcWidth) {
|
||||
GLfloat vertices[] = {
|
||||
1.f, -1.f,
|
||||
(float)srcFmtWidth, (float)srcHeight,
|
||||
1.f, 1.f,
|
||||
(float)srcFmtWidth, 0.f,
|
||||
-1.f, -1.f,
|
||||
0.f, (float)srcHeight,
|
||||
-1.f, 1.f,
|
||||
0.f, 0.f
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*4*4, vertices, GL_STREAM_DRAW);
|
||||
|
||||
s_cached_srcHeight = srcHeight;
|
||||
s_cached_srcWidth = srcWidth;
|
||||
}
|
||||
|
||||
glBindVertexArray( s_decode_VAO );
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace OGL
|
||||
34
Source/Core/VideoBackends/OGL/Src/TextureConverter.h
Normal file
34
Source/Core/VideoBackends/OGL/Src/TextureConverter.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _TEXTURECONVERTER_H_
|
||||
#define _TEXTURECONVERTER_H_
|
||||
|
||||
#include "VideoCommon.h"
|
||||
#include "GLUtil.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
// Converts textures between formats using shaders
|
||||
// TODO: support multiple texture formats
|
||||
namespace TextureConverter
|
||||
{
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
|
||||
u8* destAddr, int dstWidth, int dstHeight);
|
||||
|
||||
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
|
||||
|
||||
// returns size of the encoded data (in bytes)
|
||||
int EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
|
||||
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
|
||||
#endif // _TEXTURECONVERTER_H_
|
||||
355
Source/Core/VideoBackends/OGL/Src/VertexManager.cpp
Normal file
355
Source/Core/VideoBackends/OGL/Src/VertexManager.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "Fifo.h"
|
||||
|
||||
#include "DriverDetails.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "Statistics.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "Render.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "BPMemory.h"
|
||||
#include "TextureCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "VertexManager.h"
|
||||
#include "IndexGenerator.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "PerfQueryBase.h"
|
||||
#include "Render.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
// internal state for loading vertices
|
||||
extern NativeVertexFormat *g_nativeVertexFmt;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
//This are the initially requested size for the buffers expressed in bytes
|
||||
const u32 MAX_IBUFFER_SIZE = 2*1024*1024;
|
||||
const u32 MAX_VBUFFER_SIZE = 16*1024*1024;
|
||||
|
||||
static StreamBuffer *s_vertexBuffer;
|
||||
static StreamBuffer *s_indexBuffer;
|
||||
static u32 s_baseVertex;
|
||||
static u32 s_offset[3];
|
||||
|
||||
VertexManager::VertexManager()
|
||||
{
|
||||
CreateDeviceObjects();
|
||||
}
|
||||
|
||||
VertexManager::~VertexManager()
|
||||
{
|
||||
DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void VertexManager::CreateDeviceObjects()
|
||||
{
|
||||
s_vertexBuffer = new StreamBuffer(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE);
|
||||
m_vertex_buffers = s_vertexBuffer->getBuffer();
|
||||
|
||||
s_indexBuffer = new StreamBuffer(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE);
|
||||
m_index_buffers = s_indexBuffer->getBuffer();
|
||||
|
||||
m_CurrentVertexFmt = NULL;
|
||||
m_last_vao = 0;
|
||||
}
|
||||
|
||||
void VertexManager::DestroyDeviceObjects()
|
||||
{
|
||||
GL_REPORT_ERRORD();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0 );
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||
GL_REPORT_ERROR();
|
||||
|
||||
delete s_vertexBuffer;
|
||||
delete s_indexBuffer;
|
||||
GL_REPORT_ERROR();
|
||||
}
|
||||
|
||||
void VertexManager::PrepareDrawBuffers(u32 stride)
|
||||
{
|
||||
u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride;
|
||||
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
|
||||
u32 line_index_size = IndexGenerator::GetLineindexLen();
|
||||
u32 point_index_size = IndexGenerator::GetPointindexLen();
|
||||
u32 index_size = (triangle_index_size+line_index_size+point_index_size) * sizeof(u16);
|
||||
|
||||
s_vertexBuffer->Alloc(vertex_data_size, stride);
|
||||
u32 offset = s_vertexBuffer->Upload(GetVertexBuffer(), vertex_data_size);
|
||||
s_baseVertex = offset / stride;
|
||||
|
||||
s_indexBuffer->Alloc(index_size);
|
||||
if(triangle_index_size)
|
||||
{
|
||||
s_offset[0] = s_indexBuffer->Upload((u8*)GetTriangleIndexBuffer(), triangle_index_size * sizeof(u16));
|
||||
}
|
||||
if(line_index_size)
|
||||
{
|
||||
s_offset[1] = s_indexBuffer->Upload((u8*)GetLineIndexBuffer(), line_index_size * sizeof(u16));
|
||||
}
|
||||
if(point_index_size)
|
||||
{
|
||||
s_offset[2] = s_indexBuffer->Upload((u8*)GetPointIndexBuffer(), point_index_size * sizeof(u16));
|
||||
}
|
||||
|
||||
ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size);
|
||||
ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_size);
|
||||
}
|
||||
|
||||
void VertexManager::Draw(u32 stride)
|
||||
{
|
||||
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
|
||||
u32 line_index_size = IndexGenerator::GetLineindexLen();
|
||||
u32 point_index_size = IndexGenerator::GetPointindexLen();
|
||||
u32 max_index = IndexGenerator::GetNumVerts();
|
||||
GLenum triangle_mode = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart?GL_TRIANGLE_STRIP:GL_TRIANGLES;
|
||||
|
||||
if(g_ogl_config.bSupportsGLBaseVertex) {
|
||||
if (triangle_index_size > 0)
|
||||
{
|
||||
glDrawRangeElementsBaseVertex(triangle_mode, 0, max_index, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (line_index_size > 0)
|
||||
{
|
||||
glDrawRangeElementsBaseVertex(GL_LINES, 0, max_index, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (point_index_size > 0)
|
||||
{
|
||||
glDrawRangeElementsBaseVertex(GL_POINTS, 0, max_index, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2], s_baseVertex);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
}
|
||||
else if (DriverDetails::HasBug(DriverDetails::BUG_ISTEGRA))
|
||||
{
|
||||
if (triangle_index_size > 0)
|
||||
{
|
||||
glDrawElements(triangle_mode, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (line_index_size > 0)
|
||||
{
|
||||
glDrawElements(GL_LINES, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (point_index_size > 0)
|
||||
{
|
||||
glDrawElements(GL_POINTS, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
} else {
|
||||
if (triangle_index_size > 0)
|
||||
{
|
||||
glDrawRangeElements(triangle_mode, 0, max_index, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (line_index_size > 0)
|
||||
{
|
||||
glDrawRangeElements(GL_LINES, 0, max_index, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
if (point_index_size > 0)
|
||||
{
|
||||
glDrawRangeElements(GL_POINTS, 0, max_index, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2]);
|
||||
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VertexManager::vFlush()
|
||||
{
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfregs.numTexGen.numTexGens,
|
||||
xfregs.numChan.numColorChans, xfregs.dualTexTrans.enabled, bpmem.ztex2.op,
|
||||
bpmem.blendmode.colorupdate, bpmem.blendmode.alphaupdate, bpmem.zmode.updateenable);
|
||||
|
||||
for (unsigned int i = 0; i < xfregs.numChan.numColorChans; ++i)
|
||||
{
|
||||
LitChannel* ch = &xfregs.color[i];
|
||||
PRIM_LOG("colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc);
|
||||
ch = &xfregs.alpha[i];
|
||||
PRIM_LOG("alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i, ch->matsource, ch->GetFullLightMask(), ch->ambsource, ch->diffusefunc, ch->attnfunc);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i)
|
||||
{
|
||||
TexMtxInfo tinfo = xfregs.texMtxInfo[i];
|
||||
if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP) tinfo.hex &= 0x7ff;
|
||||
if (tinfo.texgentype != XF_TEXGEN_REGULAR) tinfo.projection = 0;
|
||||
|
||||
PRIM_LOG("txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, postmtx=%d, postnorm=%d",
|
||||
i, tinfo.projection, tinfo.inputform, tinfo.texgentype, tinfo.sourcerow, tinfo.embosssourceshift, tinfo.embosslightshift,
|
||||
xfregs.postMtxInfo[i].index, xfregs.postMtxInfo[i].normalize);
|
||||
}
|
||||
|
||||
PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphatest=0x%x", bpmem.genMode.numtevstages+1, bpmem.genMode.numindstages,
|
||||
bpmem.genMode.numtexgens, (u32)bpmem.dstalpha.enable, (bpmem.alpha_test.hex>>16)&0xff);
|
||||
#endif
|
||||
|
||||
(void)GL_REPORT_ERROR();
|
||||
|
||||
GLVertexFormat *nativeVertexFmt = (GLVertexFormat*)g_nativeVertexFmt;
|
||||
u32 stride = nativeVertexFmt->GetVertexStride();
|
||||
|
||||
if(m_last_vao != nativeVertexFmt->VAO) {
|
||||
glBindVertexArray(nativeVertexFmt->VAO);
|
||||
m_last_vao = nativeVertexFmt->VAO;
|
||||
}
|
||||
|
||||
PrepareDrawBuffers(stride);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
u32 usedtextures = 0;
|
||||
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
|
||||
if (bpmem.tevorders[i / 2].getEnable(i & 1))
|
||||
usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1);
|
||||
|
||||
if (bpmem.genMode.numindstages > 0)
|
||||
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
|
||||
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
|
||||
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
|
||||
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if (usedtextures & (1 << i))
|
||||
{
|
||||
TextureCache::SetNextStage(i);
|
||||
g_renderer->SetSamplerState(i % 4, i / 4);
|
||||
FourTexUnits &tex = bpmem.tex[i >> 2];
|
||||
TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i,
|
||||
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
|
||||
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
|
||||
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
|
||||
tex.texTlut[i&3].tlut_format,
|
||||
(tex.texMode0[i&3].min_filter & 3),
|
||||
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
|
||||
tex.texImage1[i&3].image_type);
|
||||
|
||||
if (tentry)
|
||||
{
|
||||
// 0s are probably for no manual wrapping needed.
|
||||
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Error loading texture");
|
||||
}
|
||||
}
|
||||
|
||||
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate
|
||||
&& bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
|
||||
|
||||
// Makes sure we can actually do Dual source blending
|
||||
bool dualSourcePossible = g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
|
||||
|
||||
// finally bind
|
||||
if (dualSourcePossible)
|
||||
{
|
||||
if (useDstAlpha)
|
||||
{
|
||||
// If host supports GL_ARB_blend_func_extended, we can do dst alpha in
|
||||
// the same pass as regular rendering.
|
||||
ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, g_nativeVertexFmt->m_components);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
|
||||
}
|
||||
|
||||
// set global constants
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
ProgramShaderCache::UploadConstants();
|
||||
|
||||
// setup the pointers
|
||||
if (g_nativeVertexFmt)
|
||||
g_nativeVertexFmt->SetupVertexPointers();
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
Draw(stride);
|
||||
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
//ERROR_LOG(VIDEO, "PerfQuery result: %d", g_perf_query->GetQueryResult(bpmem.zcontrol.early_ztest ? PQ_ZCOMP_OUTPUT_ZCOMPLOC : PQ_ZCOMP_OUTPUT));
|
||||
|
||||
// run through vertex groups again to set alpha
|
||||
if (useDstAlpha && !dualSourcePossible)
|
||||
{
|
||||
ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS,g_nativeVertexFmt->m_components);
|
||||
if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
// Need to set these again, if we don't support UBO
|
||||
VertexShaderManager::SetConstants();
|
||||
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
|
||||
}
|
||||
|
||||
// only update alpha
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
Draw(stride);
|
||||
|
||||
// restore color mask
|
||||
g_renderer->SetColorMask();
|
||||
|
||||
if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract)
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
|
||||
{
|
||||
// save the shaders
|
||||
ProgramShaderCache::PCacheEntry prog = ProgramShaderCache::GetShaderProgram();
|
||||
char strfile[255];
|
||||
sprintf(strfile, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
|
||||
std::ofstream fps;
|
||||
OpenFStream(fps, strfile, std::ios_base::out);
|
||||
fps << prog.shader.strpprog.c_str();
|
||||
sprintf(strfile, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
|
||||
std::ofstream fvs;
|
||||
OpenFStream(fvs, strfile, std::ios_base::out);
|
||||
fvs << prog.shader.strvprog.c_str();
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.iLog & CONF_SAVETARGETS)
|
||||
{
|
||||
char str[128];
|
||||
sprintf(str, "%starg%.3d.tga", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
|
||||
TargetRectangle tr;
|
||||
tr.left = 0;
|
||||
tr.right = Renderer::GetTargetWidth();
|
||||
tr.top = 0;
|
||||
tr.bottom = Renderer::GetTargetHeight();
|
||||
g_renderer->SaveScreenshot(str, tr);
|
||||
}
|
||||
#endif
|
||||
g_Config.iSaveTargetId++;
|
||||
|
||||
ClearEFBCache();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
52
Source/Core/VideoBackends/OGL/Src/VertexManager.h
Normal file
52
Source/Core/VideoBackends/OGL/Src/VertexManager.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _VERTEXMANAGER_H_
|
||||
#define _VERTEXMANAGER_H_
|
||||
|
||||
#include "CPMemory.h"
|
||||
|
||||
#include "VertexManagerBase.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class GLVertexFormat : public NativeVertexFormat
|
||||
{
|
||||
PortableVertexDeclaration vtx_decl;
|
||||
|
||||
public:
|
||||
GLVertexFormat();
|
||||
~GLVertexFormat();
|
||||
|
||||
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
||||
virtual void SetupVertexPointers();
|
||||
|
||||
GLuint VAO;
|
||||
};
|
||||
|
||||
// Handles the OpenGL details of drawing lots of vertices quickly.
|
||||
// Other functionality is moving out.
|
||||
class VertexManager : public ::VertexManager
|
||||
{
|
||||
public:
|
||||
VertexManager();
|
||||
~VertexManager();
|
||||
NativeVertexFormat* CreateNativeVertexFormat();
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
// NativeVertexFormat use this
|
||||
GLuint m_vertex_buffers;
|
||||
GLuint m_index_buffers;
|
||||
GLuint m_last_vao;
|
||||
private:
|
||||
void Draw(u32 stride);
|
||||
void vFlush();
|
||||
void PrepareDrawBuffers(u32 stride);
|
||||
NativeVertexFormat *m_CurrentVertexFmt;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _VERTEXMANAGER_H_
|
||||
130
Source/Core/VideoBackends/OGL/Src/VertexShaderCache.cpp
Normal file
130
Source/Core/VideoBackends/OGL/Src/VertexShaderCache.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "GLUtil.h"
|
||||
|
||||
#include "Render.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "VertexManager.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "XFMemory.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "FileUtil.h"
|
||||
#include "Debugger.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
void SetVSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
|
||||
{
|
||||
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
|
||||
for (int a = 0; a < NUM_UNIFORMS; ++a)
|
||||
{
|
||||
if (!strcmp(name, UniformNames[a]))
|
||||
{
|
||||
if (tmp.shader.UniformLocations[a] == -1)
|
||||
return;
|
||||
else if (tmp.shader.UniformSize[a] <= offset)
|
||||
return;
|
||||
else
|
||||
{
|
||||
unsigned int maxcount= tmp.shader.UniformSize[a]-offset;
|
||||
glUniform4fv(tmp.shader.UniformLocations[a] + offset, std::min(count, maxcount), f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
float const buf[4] = {f1, f2, f3, f4};
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetVSConstant4fv(unsigned int const_number, const float *f)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, 1);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
|
||||
{
|
||||
float buf[4 * C_VENVCONST_END];
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
buf[4*i ] = *f++;
|
||||
buf[4*i+1] = *f++;
|
||||
buf[4*i+2] = *f++;
|
||||
buf[4*i+3] = 0.f;
|
||||
}
|
||||
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
|
||||
{
|
||||
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, count);
|
||||
return;
|
||||
}
|
||||
for (unsigned int a = 0; a < 9; ++a)
|
||||
{
|
||||
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
|
||||
{
|
||||
unsigned int offset = const_number - VSVar_Loc[a].reg;
|
||||
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf, count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OGL
|
||||
29
Source/Core/VideoBackends/OGL/Src/VideoBackend.h
Normal file
29
Source/Core/VideoBackends/OGL/Src/VideoBackend.h
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef OGL_VIDEO_BACKEND_H_
|
||||
#define OGL_VIDEO_BACKEND_H_
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
class VideoBackend : public VideoBackendHardware
|
||||
{
|
||||
bool Initialize(void *&);
|
||||
void Shutdown();
|
||||
|
||||
std::string GetName();
|
||||
std::string GetDisplayName();
|
||||
|
||||
void Video_Prepare();
|
||||
void Video_Cleanup();
|
||||
|
||||
void ShowConfig(void* parent);
|
||||
|
||||
void UpdateFPSDisplay(const char*);
|
||||
unsigned int PeekMessages();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
277
Source/Core/VideoBackends/OGL/Src/main.cpp
Normal file
277
Source/Core/VideoBackends/OGL/Src/main.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
|
||||
// OpenGL Backend Documentation
|
||||
/*
|
||||
|
||||
1.1 Display settings
|
||||
|
||||
Internal and fullscreen resolution: Since the only internal resolutions allowed
|
||||
are also fullscreen resolution allowed by the system there is only need for one
|
||||
resolution setting that applies to both the internal resolution and the
|
||||
fullscreen resolution. - Apparently no, someone else doesn't agree
|
||||
|
||||
Todo: Make the internal resolution option apply instantly, currently only the
|
||||
native and 2x option applies instantly. To do this we need to be able to change
|
||||
the reinitialize FramebufferManager:Init() while a game is running.
|
||||
|
||||
1.2 Screenshots
|
||||
|
||||
|
||||
The screenshots should be taken from the internal representation of the picture
|
||||
regardless of what the current window size is. Since AA and wireframe is
|
||||
applied together with the picture resizing this rule is not currently applied
|
||||
to AA or wireframe pictures, they are instead taken from whatever the window
|
||||
size is.
|
||||
|
||||
Todo: Render AA and wireframe to a separate picture used for the screenshot in
|
||||
addition to the one for display.
|
||||
|
||||
1.3 AA
|
||||
|
||||
Make AA apply instantly during gameplay if possible
|
||||
|
||||
*/
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Atomic.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "Thread.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "EmuWindow.h"
|
||||
#include "IniFile.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include "VideoConfigDiag.h"
|
||||
#include "Debugger/DebuggerPanel.h"
|
||||
#endif // HAVE_WX
|
||||
|
||||
#include "MainBase.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "LookUpTables.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "Render.h"
|
||||
#include "GLUtil.h"
|
||||
#include "Fifo.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "TextureCache.h"
|
||||
#include "BPStructs.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "VertexLoaderManager.h"
|
||||
#include "VertexManager.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "ProgramShaderCache.h"
|
||||
#include "CommandProcessor.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "TextureConverter.h"
|
||||
#include "PostProcessing.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "DLCache.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "Core.h"
|
||||
#include "Host.h"
|
||||
#include "SamplerCache.h"
|
||||
#include "PerfQuery.h"
|
||||
|
||||
#include "VideoState.h"
|
||||
#include "IndexGenerator.h"
|
||||
#include "VideoBackend.h"
|
||||
#include "ConfigManager.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
std::string VideoBackend::GetName()
|
||||
{
|
||||
return "OGL";
|
||||
}
|
||||
|
||||
std::string VideoBackend::GetDisplayName()
|
||||
{
|
||||
return "OpenGL";
|
||||
}
|
||||
|
||||
void GetShaders(std::vector<std::string> &shaders)
|
||||
{
|
||||
std::set<std::string> already_found;
|
||||
|
||||
shaders.clear();
|
||||
static const std::string directories[] = {
|
||||
File::GetUserPath(D_SHADERS_IDX),
|
||||
File::GetSysDirectory() + SHADERS_DIR DIR_SEP,
|
||||
};
|
||||
for (size_t i = 0; i < ArraySize(directories); ++i)
|
||||
{
|
||||
if (!File::IsDirectory(directories[i]))
|
||||
continue;
|
||||
|
||||
File::FSTEntry entry;
|
||||
File::ScanDirectoryTree(directories[i], entry);
|
||||
for (u32 j = 0; j < entry.children.size(); j++)
|
||||
{
|
||||
std::string name = entry.children[j].virtualName.c_str();
|
||||
if (name.size() < 5)
|
||||
continue;
|
||||
if (strcasecmp(name.substr(name.size() - 5).c_str(), ".glsl"))
|
||||
continue;
|
||||
|
||||
name = name.substr(0, name.size() - 5);
|
||||
if (already_found.find(name) != already_found.end())
|
||||
continue;
|
||||
|
||||
already_found.insert(name);
|
||||
shaders.push_back(name);
|
||||
}
|
||||
}
|
||||
std::sort(shaders.begin(), shaders.end());
|
||||
}
|
||||
|
||||
void InitBackendInfo()
|
||||
{
|
||||
g_Config.backend_info.APIType = API_OPENGL;
|
||||
g_Config.backend_info.bUseRGBATextures = true;
|
||||
g_Config.backend_info.bUseMinimalMipCount = false;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
//g_Config.backend_info.bSupportsDualSourceBlend = true; // is gpu dependent and must be set in renderer
|
||||
g_Config.backend_info.bSupportsFormatReinterpretation = true;
|
||||
g_Config.backend_info.bSupportsPixelLighting = true;
|
||||
//g_Config.backend_info.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer
|
||||
|
||||
// aamodes
|
||||
const char* caamodes[] = {_trans("None"), "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"};
|
||||
g_Config.backend_info.AAModes.assign(caamodes, caamodes + sizeof(caamodes)/sizeof(*caamodes));
|
||||
|
||||
// pp shaders
|
||||
GetShaders(g_Config.backend_info.PPShaders);
|
||||
}
|
||||
|
||||
void VideoBackend::ShowConfig(void *_hParent)
|
||||
{
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
InitBackendInfo();
|
||||
VideoConfigDiag diag((wxWindow*)_hParent, "OpenGL", "gfx_opengl");
|
||||
diag.ShowModal();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void *&window_handle)
|
||||
{
|
||||
InitializeShared();
|
||||
InitBackendInfo();
|
||||
|
||||
frameCount = 0;
|
||||
|
||||
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_opengl.ini").c_str());
|
||||
g_Config.GameIniLoad();
|
||||
g_Config.UpdateProjectionHack();
|
||||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
||||
InitInterface();
|
||||
if (!GLInterface->Create(window_handle))
|
||||
return false;
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::OSD_INIT);
|
||||
|
||||
s_BackendInitialized = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is called after Initialize() from the Core
|
||||
// Run from the graphics thread
|
||||
void VideoBackend::Video_Prepare()
|
||||
{
|
||||
GLInterface->MakeCurrent();
|
||||
|
||||
g_renderer = new Renderer;
|
||||
|
||||
s_efbAccessRequested = false;
|
||||
s_FifoShuttingDown = false;
|
||||
s_swapRequested = false;
|
||||
|
||||
CommandProcessor::Init();
|
||||
PixelEngine::Init();
|
||||
|
||||
BPInit();
|
||||
g_vertex_manager = new VertexManager;
|
||||
g_perf_query = new PerfQuery;
|
||||
Fifo_Init(); // must be done before OpcodeDecoder_Init()
|
||||
OpcodeDecoder_Init();
|
||||
IndexGenerator::Init();
|
||||
VertexShaderManager::Init();
|
||||
PixelShaderManager::Init();
|
||||
ProgramShaderCache::Init();
|
||||
PostProcessing::Init();
|
||||
g_texture_cache = new TextureCache();
|
||||
g_sampler_cache = new SamplerCache();
|
||||
Renderer::Init();
|
||||
GL_REPORT_ERRORD();
|
||||
VertexLoaderManager::Init();
|
||||
TextureConverter::Init();
|
||||
#ifndef _M_GENERIC
|
||||
DLCache::Init();
|
||||
#endif
|
||||
|
||||
// Notify the core that the video backend is ready
|
||||
Host_Message(WM_USER_CREATE);
|
||||
}
|
||||
|
||||
void VideoBackend::Shutdown()
|
||||
{
|
||||
s_BackendInitialized = false;
|
||||
|
||||
// Do our OSD callbacks
|
||||
OSD::DoCallbacks(OSD::OSD_SHUTDOWN);
|
||||
|
||||
GLInterface->Shutdown();
|
||||
}
|
||||
|
||||
void VideoBackend::Video_Cleanup() {
|
||||
|
||||
if (g_renderer)
|
||||
{
|
||||
s_efbAccessRequested = false;
|
||||
s_FifoShuttingDown = false;
|
||||
s_swapRequested = false;
|
||||
#ifndef _M_GENERIC
|
||||
DLCache::Shutdown();
|
||||
#endif
|
||||
Fifo_Shutdown();
|
||||
|
||||
// The following calls are NOT Thread Safe
|
||||
// And need to be called from the video thread
|
||||
Renderer::Shutdown();
|
||||
TextureConverter::Shutdown();
|
||||
VertexLoaderManager::Shutdown();
|
||||
delete g_sampler_cache;
|
||||
g_sampler_cache = NULL;
|
||||
delete g_texture_cache;
|
||||
g_texture_cache = NULL;
|
||||
PostProcessing::Shutdown();
|
||||
ProgramShaderCache::Shutdown();
|
||||
VertexShaderManager::Shutdown();
|
||||
PixelShaderManager::Shutdown();
|
||||
delete g_perf_query;
|
||||
g_perf_query = NULL;
|
||||
delete g_vertex_manager;
|
||||
g_vertex_manager = NULL;
|
||||
OpcodeDecoder_Shutdown();
|
||||
delete g_renderer;
|
||||
g_renderer = NULL;
|
||||
GLInterface->ClearCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
10
Source/Core/VideoBackends/OGL/Src/main.h
Normal file
10
Source/Core/VideoBackends/OGL/Src/main.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _MAIN_H_
|
||||
#define _MAIN_H_
|
||||
|
||||
#include "MainBase.h"
|
||||
|
||||
#endif // _MAIN_H_
|
||||
5
Source/Core/VideoBackends/OGL/Src/stdafx.cpp
Normal file
5
Source/Core/VideoBackends/OGL/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"
|
||||
12
Source/Core/VideoBackends/OGL/Src/stdafx.h
Normal file
12
Source/Core/VideoBackends/OGL/Src/stdafx.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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>
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user