Adding software rendering plugin. This is aimed at accurate emulation, not fast. Its more like a debugging tool than actually useful.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4407 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
donkopunchstania 2009-10-12 00:48:24 +00:00
parent ab8d182c37
commit 9b16c36014
58 changed files with 10272 additions and 0 deletions

View File

@ -191,6 +191,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxCore28", "..\Externals\wx
{1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE} = {1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Plugin_VideoSoftware", "Plugins\Plugin_VideoSoftware\Plugin_VideoSoftware.vcproj", "{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -672,6 +674,18 @@ Global
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|Win32.Build.0 = Release|Win32
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|x64.ActiveCfg = Release|x64
{11F55366-12EC-4C44-A8CB-1D4E315D61ED}.Release|x64.Build.0 = Release|x64
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|Win32.ActiveCfg = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|Win32.Build.0 = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Debug|x64.ActiveCfg = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|Win32.ActiveCfg = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|Win32.Build.0 = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.DebugFast|x64.ActiveCfg = Debug|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|Win32.ActiveCfg = Release|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|Win32.Build.0 = Release|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release_JITIL|x64.ActiveCfg = Release|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|Win32.ActiveCfg = Release|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|Win32.Build.0 = Release|Win32
{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,481 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="Plugin_VideoSoftware"
ProjectGUID="{66A4E7BD-E2E8-4373-9B75-8750EB5AE683}"
RootNamespace="Plugin_VideoSoftware"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_WIN32;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/VideoSoftware.pch"
AssemblerListingLocation="$(IntDir)\"
ProgramDataBaseFileName="$(IntDir)\"
WarningLevel="3"
DebugInformationFormat="3"
ForcedIncludeFiles="stdafx.h"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
IgnoreImportLibrary="false"
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib common.lib wxbase28ud.lib wxmsw28ud_core.lib"
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoSWD.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;..\..\core\common\$(PlatformName)\$(ConfigurationName)&quot;;..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;&quot;..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)&quot;"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="0"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="../../PluginSpecs;../../Core/Common/Src;../../Core/InputCommon/Src;./Src;./Src/Windows;../../../Externals;..\..\..\Externals\libjpeg;..\..\..\Externals\wxWidgets\Include;..\..\..\Externals\wxWidgets\Include\msvc;..\..\..\Externals\Glew"
PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;_WIN32;PLUGIN_VIDEOSOFTWARE_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_SECURE_SCL=0"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile="$(IntDir)/VideoSoftware.pch"
WarningLevel="3"
DebugInformationFormat="3"
ForcedIncludeFiles="stdafx.h"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
IgnoreImportLibrary="false"
AdditionalDependencies="odbc32.lib odbccp32.lib comctl32.lib winmm.lib opengl32.lib glew32s.lib glu32.lib rpcrt4.lib libjpeg.lib common.lib wxbase28u.lib wxmsw28u_core.lib"
OutputFile="..\..\..\Binary\Win32/Plugins\Plugin_VideoSW.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;..\..\core\common\$(PlatformName)\$(ConfigurationName)&quot;;..\..\..\Externals\Cg;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg;&quot;..\..\..\Externals\wxWidgets\lib\vc_lib\$(PlatformName)&quot;"
IgnoreAllDefaultLibraries="false"
IgnoreDefaultLibraryNames="msvcprt.lib;libcmt.lib"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(PlatformName)\$(ConfigurationName)\$(TargetName).pdb"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(PlatformName)\$(ConfigurationName)\$(TargetName).lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Common"
>
<File
RelativePath="..\..\Core\VideoCommon\Src\ImageWrite.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\memcpy_amd.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\NativeVertexWriter.cpp"
>
</File>
<File
RelativePath=".\Src\NativeVertexWriter.h"
>
</File>
<File
RelativePath="..\Plugin_VideoOGL\Src\rasterfont.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\TextureDecoder.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Color.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Normal.cpp"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_Position.cpp"
>
</File>
<File
RelativePath=".\Src\VertexLoader_Position.h"
>
</File>
<File
RelativePath="..\..\Core\VideoCommon\Src\VertexLoader_TextCoord.cpp"
>
</File>
<File
RelativePath=".\Src\VideoCommon.h"
>
</File>
</Filter>
<Filter
Name="Win32"
>
<File
RelativePath=".\Src\Win32.cpp"
>
</File>
<File
RelativePath=".\Src\Win32.h"
>
</File>
</Filter>
<File
RelativePath=".\Src\BPMemLoader.cpp"
>
</File>
<File
RelativePath=".\Src\BPMemLoader.h"
>
</File>
<File
RelativePath=".\Src\Clipper.cpp"
>
</File>
<File
RelativePath=".\Src\Clipper.h"
>
</File>
<File
RelativePath=".\Src\CommandProcessor.cpp"
>
</File>
<File
RelativePath=".\Src\CommandProcessor.h"
>
</File>
<File
RelativePath=".\Src\CPMemLoader.cpp"
>
</File>
<File
RelativePath=".\Src\CPMemLoader.h"
>
</File>
<File
RelativePath=".\Src\DebugUtil.cpp"
>
</File>
<File
RelativePath=".\Src\DebugUtil.h"
>
</File>
<File
RelativePath=".\Src\EfbCopy.cpp"
>
</File>
<File
RelativePath=".\Src\EfbCopy.h"
>
</File>
<File
RelativePath=".\Src\EfbInterface.cpp"
>
</File>
<File
RelativePath=".\Src\EfbInterface.h"
>
</File>
<File
RelativePath=".\Src\GLUtil.cpp"
>
</File>
<File
RelativePath=".\Src\GLUtil.h"
>
</File>
<File
RelativePath=".\Src\HwRasterizer.cpp"
>
</File>
<File
RelativePath=".\Src\HwRasterizer.h"
>
</File>
<File
RelativePath=".\Src\main.cpp"
>
</File>
<File
RelativePath=".\Src\main.h"
>
</File>
<File
RelativePath=".\Src\NativeVertexFormat.h"
>
</File>
<File
RelativePath=".\Src\OpcodeDecoder.cpp"
>
</File>
<File
RelativePath=".\Src\OpcodeDecoder.h"
>
</File>
<File
RelativePath=".\Src\PixelEngine.cpp"
>
</File>
<File
RelativePath=".\Src\PixelEngine.h"
>
</File>
<File
RelativePath=".\Src\Rasterizer.cpp"
>
</File>
<File
RelativePath=".\Src\Rasterizer.h"
>
</File>
<File
RelativePath=".\Src\Renderer.cpp"
>
</File>
<File
RelativePath=".\Src\Renderer.h"
>
</File>
<File
RelativePath=".\Src\SetupUnit.cpp"
>
</File>
<File
RelativePath=".\Src\SetupUnit.h"
>
</File>
<File
RelativePath=".\Src\Statistics.cpp"
>
</File>
<File
RelativePath=".\Src\Statistics.h"
>
</File>
<File
RelativePath=".\Src\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\stdafx.h"
>
</File>
<File
RelativePath=".\Src\Tev.cpp"
>
</File>
<File
RelativePath=".\Src\Tev.h"
>
</File>
<File
RelativePath=".\Src\TextureEncoder.cpp"
>
</File>
<File
RelativePath=".\Src\TextureEncoder.h"
>
</File>
<File
RelativePath=".\Src\TextureSampler.cpp"
>
</File>
<File
RelativePath=".\Src\TextureSampler.h"
>
</File>
<File
RelativePath=".\Src\TransformUnit.cpp"
>
</File>
<File
RelativePath=".\Src\TransformUnit.h"
>
</File>
<File
RelativePath=".\Src\VertexFormatConverter.cpp"
>
</File>
<File
RelativePath=".\Src\VertexFormatConverter.h"
>
</File>
<File
RelativePath=".\Src\VertexLoader.cpp"
>
</File>
<File
RelativePath=".\Src\VertexLoader.h"
>
</File>
<File
RelativePath=".\Src\VideoConfig.cpp"
>
</File>
<File
RelativePath=".\Src\VideoConfig.h"
>
</File>
<File
RelativePath=".\Src\XFMemLoader.cpp"
>
</File>
<File
RelativePath=".\Src\XFMemLoader.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,149 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "pluginspecs_video.h"
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "Rasterizer.h"
#include "PixelEngine.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
BPMemory bpmem;
void InitBPMemory()
{
memset(&bpmem, 0, sizeof(bpmem));
bpmem.bpMask = 0xFFFFFF;
}
void BPWritten(int address, int newvalue);
void LoadBPReg(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;
BPWritten(address, newval);
}
void BPWritten(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:
PixelEngine::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));
PixelEngine::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));
PixelEngine::SetToken(static_cast<u16>(bpmem.petokenint & 0xFFFF), TRUE);
break;
case BPMEM_TRIGGER_EFB_COPY:
EfbCopy::CopyEfb();
break;
case BPMEM_CLEARBBOX1:
PixelEngine::pereg.boxRight = newvalue >> 10;
PixelEngine::pereg.boxLeft = newvalue & 0x3ff;
break;
case BPMEM_CLEARBBOX2:
PixelEngine::pereg.boxBottom = newvalue >> 10;
PixelEngine::pereg.boxTop = newvalue & 0x3ff;
break;
case BPMEM_LOADTLUT0: // Load a Texture Look Up Table
case BPMEM_LOADTLUT1:
{
u32 tlutTMemAddr = (newvalue & 0x3FF) << 9;
u32 tlutXferCount = (newvalue & 0x1FFC00) >> 5;
u8 *ptr = 0;
// TODO - figure out a cleaner way.
if (g_VideoInitialize.bWii)
ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.tlutXferSrc << 5);
else
ptr = g_VideoInitialize.pGetMemoryPointer((bpmem.tlutXferSrc & 0xFFFFF) << 5);
if (ptr)
memcpy_gc(texMem + tlutTMemAddr, ptr, tlutXferCount);
else
PanicAlert("Invalid palette pointer %08x %08x %08x", bpmem.tlutXferSrc, bpmem.tlutXferSrc << 5, (bpmem.tlutXferSrc & 0xFFFFF)<< 5);
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, 3, konst, reg.b); // A
Rasterizer::SetTevReg(regNum, 0, 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, 1, konst, reg.b); // G
Rasterizer::SetTevReg(regNum, 2, konst, reg.a); // B
break;
}
}
}

View File

@ -0,0 +1,28 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _BPMEMLOADER_H_
#define _BPMEMLOADER_H_
#include "Common.h"
#include "../../../Core/VideoCommon/Src/BPMemory.h"
void InitBPMemory();
#endif

View File

@ -0,0 +1,82 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoCommon.h"
#include "CPMemLoader.h"
// CP state
u8 *cached_arraybases[16];
// STATE_TO_SAVE
u32 arraybases[16];
u32 arraystrides[16];
TMatrixIndexA MatrixIndexA;
TMatrixIndexB MatrixIndexB;
TVtxDesc g_VtxDesc;
VAT g_VtxAttr[8];
void LoadCPReg(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_GetPtr(value);
break;
case 0xB0:
arraystrides[sub_cmd & 0xF] = value & 0xFF;
break;
}
}

View File

@ -0,0 +1,27 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CPMEMLOADER_H_
#define _CPMEMLOADER_H_
#include "Common.h"
#include "../../../Core/VideoCommon/Src/CPMemory.h"
#endif

View File

@ -0,0 +1,300 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/*
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 "Statistics.h"
#include "VideoConfig.h"
namespace Clipper
{
void Init()
{
for (int i = 0; i < 18; ++i)
Vertices[i+3] = &ClippedVertices[i];
}
void SetViewOffset()
{
m_ViewOffset[0] = xfregs.viewport.xOrig - 342;
m_ViewOffset[1] = xfregs.viewport.yOrig - 342;
m_ViewOffset[2] = xfregs.viewport.farZ - xfregs.viewport.farZ;
}
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;
float* pos = v->projectedPosition;
if (pos[3] - pos[0] < 0) cmask |= CLIP_POS_X_BIT;
if (pos[0] + pos[3] < 0) cmask |= CLIP_NEG_X_BIT;
if (pos[3] - pos[1] < 0) cmask |= CLIP_POS_Y_BIT;
if (pos[1] + pos[3] < 0) cmask |= CLIP_NEG_Y_BIT;
if (pos[3] * pos[2] > 0) cmask |= CLIP_POS_Z_BIT;
if (pos[2] + pos[3] < 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[0] * A + Vertices[I]->projectedPosition[1] * B + Vertices[I]->projectedPosition[2] * C + Vertices[I]->projectedPosition[3] * 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; \
int i; \
\
inlist[n] = inlist[0]; \
for (i = 1; i <= n; i++) { \
int idx = inlist[i]; \
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; \
} \
} \
}
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 idx = 0; idx < 3; idx += 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(stats.thisFrame.numTrianglesClipped);
// transform the poly in inlist into triangles
indices[0] = inlist[0];
indices[1] = inlist[1];
indices[2] = inlist[2];
for (int i = 3; i < n; ++i) {
indices[numIndices++] = inlist[0];
indices[numIndices++] = inlist[i - 1];
indices[numIndices++] = inlist[i];
}
}
}
}
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
if (stats.thisFrame.numDrawnObjects < g_Config.drawStart || stats.thisFrame.numDrawnObjects >= g_Config.drawEnd )
return;
INCSTAT(stats.thisFrame.numTrianglesIn)
bool backface;
if(!CullTest(v0, v1, v2, backface))
return;
int indices[21] = { 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)
{
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]]);
}
}
}
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface)
{
int mask = CalcClipMask(v0);
mask &= CalcClipMask(v1);
mask &= CalcClipMask(v2);
if(mask)
{
INCSTAT(stats.thisFrame.numTrianglesRejected)
return false;
}
float x0 = v0->projectedPosition[0];
float x1 = v1->projectedPosition[0];
float x2 = v2->projectedPosition[0];
float y1 = v1->projectedPosition[1];
float y0 = v0->projectedPosition[1];
float y2 = v2->projectedPosition[1];
float w0 = v0->projectedPosition[3];
float w1 = v1->projectedPosition[3];
float w2 = v2->projectedPosition[3];
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(stats.thisFrame.numTrianglesCulled)
return false;
}
if ((bpmem.genMode.cullmode & 2) && backface) // cull backfacing
{
INCSTAT(stats.thisFrame.numTrianglesCulled)
return false;
}
return true;
}
void PerspectiveDivide(OutputVertexData *vertex)
{
float *projected = vertex->projectedPosition;
float *screen = vertex->screenPosition;
float wInverse = 1.0f/projected[3];
screen[0] = projected[0] * wInverse * xfregs.viewport.wd + m_ViewOffset[0];
screen[1] = projected[1] * wInverse * xfregs.viewport.ht + m_ViewOffset[1];
screen[2] = projected[2] * wInverse + m_ViewOffset[2];
}
}

View File

@ -0,0 +1,46 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _CLIPPER_H_
#define _CLIPPER_H_
#include "Common.h"
#include "NativeVertexFormat.h"
namespace Clipper
{
void Init();
void SetViewOffset();
void ProcessTriangle(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
void PerspectiveDivide(OutputVertexData *vertex);
static float m_ViewOffset[3];
static OutputVertexData ClippedVertices[18];
static OutputVertexData *Vertices[21];
}
#endif

View File

@ -0,0 +1,443 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "pluginspecs_video.h"
#include "CommandProcessor.h"
#include "OpcodeDecoder.h"
#include "main.h"
#include "ChunkFile.h"
#include "MathUtil.h"
u8* g_pVideoData; // data reader uses this as the read pointer
namespace CommandProcessor
{
enum
{
GATHER_PIPE_SIZE = 32,
INT_CAUSE_CP = 0x800
};
// STATE_TO_SAVE
// variables
const int commandBufferSize = 4 * 1024;
const int commandBufferCopySize = 32;
const int maxCommandBufferWrite = commandBufferSize - commandBufferCopySize;
u8 commandBuffer[commandBufferSize];
u32 readPos;
u32 writePos;
CPReg cpreg; // shared between gfx and emulator thread
void DoState(PointerWrap &p)
{
p.Do(cpreg);
}
// function
void UpdateFifoRegister();
void UpdateInterrupts();
// does it matter that there is no synchronization between threads during writes?
inline void WriteLow (u32& _reg, u16 lowbits) {_reg = (_reg & 0xFFFF0000) | lowbits;}
inline void WriteHigh(u32& _reg, u16 highbits) {_reg = (_reg & 0x0000FFFF) | ((u32)highbits << 16);}
//inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::SyncInterlockedExchange((LONG*)&_reg,(_reg & 0xFFFF0000) | lowbits);}
//inline void WriteHigh(volatile u32& _reg, u16 highbits) {Common::SyncInterlockedExchange((LONG*)&_reg,(_reg & 0x0000FFFF) | ((u32)highbits << 16));}
inline u16 ReadLow (u32 _reg) {return (u16)(_reg & 0xFFFF);}
inline u16 ReadHigh (u32 _reg) {return (u16)(_reg >> 16);}
int et_UpdateInterrupts;
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
{
UpdateInterrupts();
}
void Init()
{
cpreg.status.Hex = 0;
cpreg.status.CommandIdle = 1;
cpreg.status.ReadIdle = 1;
cpreg.ctrl.Hex = 0;
cpreg.clear.Hex = 0;
cpreg.bboxleft = 0;
cpreg.bboxtop = 0;
cpreg.bboxright = 0;
cpreg.bboxbottom = 0;
cpreg.token = 0;
et_UpdateInterrupts = g_VideoInitialize.pRegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
// internal buffer position
readPos = 0;
writePos = 0;
g_pVideoData = 0;
}
void Shutdown()
{
#ifndef _WIN32
// delete fifo.sync;
#endif
}
void Read16(u16& _rReturnValue, const u32 _Address)
{
DEBUG_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address);
u32 regAddr = (_Address & 0xFFF) >> 1;
if (regAddr < 0x20)
_rReturnValue = ((u16*)&cpreg)[regAddr];
else
_rReturnValue = 0;
}
void RunGpu()
{
if (!g_VideoInitialize.bUseDualCore)
{
// We are going to do FP math on the main thread so have to save the current state
SaveSSEState();
LoadDefaultSSEState();
// run the opcode decoder
RunBuffer();
LoadSSEState();
}
}
void Write16(const u16 _Value, const u32 _Address)
{
INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address);
switch (_Address & 0xFFF)
{
case STATUS_REGISTER:
{
UCPStatusReg tmpStatus(_Value);
if (cpreg.status.Breakpoint != tmpStatus.Breakpoint)
INFO_LOG(COMMANDPROCESSOR,"Set breakpoint status by writing to STATUS_REGISTER");
cpreg.status.Hex = _Value;
INFO_LOG(COMMANDPROCESSOR,"\t write to STATUS_REGISTER : %04x", _Value);
}
break;
case CTRL_REGISTER:
{
cpreg.ctrl.Hex = _Value;
// clear breakpoint if BPEnable and CPIntEnable are 0
if (!cpreg.ctrl.BPEnable) {
if (!cpreg.ctrl.CPIntEnable) {
cpreg.status.Breakpoint = 0;
}
}
UpdateInterrupts();
DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value);
DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | CPULINK %s | BP %s || CPIntEnable %s | OvF %s | UndF %s"
, cpreg.ctrl.GPReadEnable ? "ON" : "OFF"
, cpreg.ctrl.GPLinkEnable ? "ON" : "OFF"
, cpreg.ctrl.BPEnable ? "ON" : "OFF"
, cpreg.ctrl.CPIntEnable ? "ON" : "OFF"
, cpreg.ctrl.FifoOverflowIntEnable ? "ON" : "OFF"
, cpreg.ctrl.FifoUnderflowIntEnable ? "ON" : "OFF"
);
}
break;
case CLEAR_REGISTER:
{
UCPClearReg tmpClear(_Value);
if (tmpClear.ClearFifoOverflow)
cpreg.status.OverflowHiWatermark = 0;
if (tmpClear.ClearFifoUnderflow)
cpreg.status.UnderflowLoWatermark = 0;
INFO_LOG(COMMANDPROCESSOR,"\t write to CLEAR_REGISTER : %04x",_Value);
}
break;
// Fifo Registers
case FIFO_TOKEN_REGISTER:
cpreg.token = _Value;
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_TOKEN_REGISTER : %04x", _Value);
break;
case FIFO_BASE_LO:
WriteLow ((u32 &)cpreg.fifobase, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_LO. FIFO base is : %08x", cpreg.fifobase);
break;
case FIFO_BASE_HI:
WriteHigh((u32 &)cpreg.fifobase, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_HI. FIFO base is : %08x", cpreg.fifobase);
break;
case FIFO_END_LO:
WriteLow ((u32 &)cpreg.fifoend, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_LO. FIFO end is : %08x", cpreg.fifoend);
break;
case FIFO_END_HI:
WriteHigh((u32 &)cpreg.fifoend, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_HI. FIFO end is : %08x", cpreg.fifoend);
break;
case FIFO_WRITE_POINTER_LO:
WriteLow ((u32 &)cpreg.writeptr, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_LO. write ptr is : %08x", cpreg.writeptr);
break;
case FIFO_WRITE_POINTER_HI:
WriteHigh ((u32 &)cpreg.writeptr, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_HI. write ptr is : %08x", cpreg.writeptr);
break;
case FIFO_READ_POINTER_LO:
WriteLow ((u32 &)cpreg.readptr, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_LO. read ptr is : %08x", cpreg.readptr);
break;
case FIFO_READ_POINTER_HI:
WriteHigh ((u32 &)cpreg.readptr, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI. read ptr is : %08x", cpreg.readptr);
break;
case FIFO_HI_WATERMARK_LO:
WriteLow ((u32 &)cpreg.hiwatermark, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_LO. hiwatermark is : %08x", cpreg.hiwatermark);
break;
case FIFO_HI_WATERMARK_HI:
WriteHigh ((u32 &)cpreg.hiwatermark, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_HI_WATERMARK_HI. hiwatermark is : %08x", cpreg.hiwatermark);
break;
case FIFO_LO_WATERMARK_LO:
WriteLow ((u32 &)cpreg.lowatermark, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_LO. lowatermark is : %08x", cpreg.lowatermark);
break;
case FIFO_LO_WATERMARK_HI:
WriteHigh ((u32 &)cpreg.lowatermark, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_LO_WATERMARK_HI. lowatermark is : %08x", cpreg.lowatermark);
break;
case FIFO_BP_LO:
WriteLow ((u32 &)cpreg.breakpt, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_LO. breakpt is : %08x", cpreg.breakpt);
break;
case FIFO_BP_HI:
WriteHigh ((u32 &)cpreg.breakpt, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BP_HI. breakpt is : %08x", cpreg.breakpt);
break;
// Super monkey try to overwrite CPReadWriteDistance by an old saved RWD value. Which is lame for us.
// hack: We have to force CPU to think fifo is alway empty and on idle.
// When we fall here CPReadWriteDistance should be always null and the game should always want to overwrite it by 0.
// So, we can skip it.
case FIFO_RW_DISTANCE_LO:
WriteLow ((u32 &)cpreg.rwdistance, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_LO. rwdistance is : %08x", cpreg.rwdistance);
break;
case FIFO_RW_DISTANCE_HI:
WriteHigh ((u32 &)cpreg.rwdistance, _Value);
DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_RW_DISTANCE_HI. rwdistance is : %08x", cpreg.rwdistance);
break;
}
RunGpu();
}
void Read32(u32& _rReturnValue, const u32 _Address)
{
_rReturnValue = 0;
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Read32 from CommandProccessor at 0x%08x", _Address);
}
void Write32(const u32 _Data, const u32 _Address)
{
_dbg_assert_msg_(COMMANDPROCESSOR, 0, "Write32 at CommandProccessor at 0x%08x", _Address);
}
void STACKALIGN GatherPipeBursted()
{
if (cpreg.ctrl.GPLinkEnable)
{
cpreg.writeptr += GATHER_PIPE_SIZE;
if (cpreg.writeptr >= (cpreg.fifoend & 0xFFFFFFE0))
cpreg.writeptr = cpreg.fifobase;
// the read/write pointers will be managed in RunGpu which will read the current fifo and
// send as much data as is available and the plugin can take
// this will have the cost of copying data to the plugin fifo buffer in the main thread
}
RunGpu();
}
void UpdateInterrupts()
{
bool bpInt = cpreg.status.Breakpoint && cpreg.ctrl.BPEnable;
bool ovfInt = cpreg.status.OverflowHiWatermark && cpreg.ctrl.FifoOverflowIntEnable;
bool undfInt = cpreg.status.UnderflowLoWatermark && cpreg.ctrl.FifoUnderflowIntEnable;
DEBUG_LOG(COMMANDPROCESSOR, "\tUpdate Interrupts");
DEBUG_LOG(COMMANDPROCESSOR, "\tCPIntEnable %s | BP %s | OvF %s | UndF %s"
, cpreg.ctrl.CPIntEnable ? "ON" : "OFF"
, cpreg.ctrl.BPEnable ? "ON" : "OFF"
, cpreg.ctrl.FifoOverflowIntEnable ? "ON" : "OFF"
, cpreg.ctrl.FifoUnderflowIntEnable ? "ON" : "OFF"
);
if (cpreg.ctrl.CPIntEnable && (bpInt || ovfInt || undfInt))
{
DEBUG_LOG(COMMANDPROCESSOR,"Interrupt set");
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, true);
}
else
{
DEBUG_LOG(COMMANDPROCESSOR,"Interrupt cleared");
g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, false);
}
}
void UpdateInterruptsFromVideoPlugin()
{
g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0);
}
void ReadFifo()
{
bool updateInterrupts = false;
cpreg.status.ReadIdle = 0;
// update rwdistance
u32 writePtr = cpreg.writeptr;
if (cpreg.readptr <= writePtr)
cpreg.rwdistance = writePtr - cpreg.readptr;
else
cpreg.rwdistance = ((cpreg.fifoend & 0xFFFFFFE0) - cpreg.fifobase) - (cpreg.readptr - writePtr);
// overflow check
cpreg.status.OverflowHiWatermark = cpreg.rwdistance < cpreg.hiwatermark?0:1;
updateInterrupts |= cpreg.ctrl.FifoOverflowIntEnable && cpreg.status.OverflowHiWatermark;
// read from fifo
u8 *ptr = g_VideoInitialize.pGetMemoryPointer(cpreg.readptr);
u32 readptr = cpreg.readptr;
u32 distance = cpreg.rwdistance;
while (distance >= commandBufferCopySize && !cpreg.status.Breakpoint && writePos < maxCommandBufferWrite)
{
// check for breakpoint
// todo - check if this is precise enough
if (cpreg.ctrl.BPEnable && (cpreg.breakpt & 0xFFFFFFE0) == (readptr & 0xFFFFFFE0))
{
cpreg.status.Breakpoint = 1;
DEBUG_LOG(VIDEO,"Hit breakpoint at %x", readptr);
if (cpreg.ctrl.CPIntEnable)
updateInterrupts = true;
}
else
{
// copy to buffer
memcpy(&commandBuffer[writePos], ptr, commandBufferCopySize);
writePos += commandBufferCopySize;
ptr += commandBufferCopySize;
readptr += commandBufferCopySize;
distance -= commandBufferCopySize;
}
if (readptr >= (cpreg.fifoend & 0xFFFFFFE0))
{
readptr = cpreg.fifobase;
ptr = g_VideoInitialize.pGetMemoryPointer(readptr);
}
}
// lock read pointer until rw distance is updated?
cpreg.readptr = readptr;
cpreg.rwdistance = distance;
// underflow check
cpreg.status.UnderflowLoWatermark = cpreg.rwdistance > cpreg.lowatermark?0:1;
updateInterrupts |= cpreg.ctrl.FifoUnderflowIntEnable && cpreg.status.UnderflowLoWatermark;
cpreg.status.ReadIdle = 1;
if (updateInterrupts)
UpdateInterruptsFromVideoPlugin();
}
bool RunBuffer()
{
// fifo is read 32 bytes at a time
// read fifo data to internal buffer
if (cpreg.ctrl.GPReadEnable)
ReadFifo();
g_pVideoData = &commandBuffer[readPos];
u32 availableBytes = writePos - readPos;
_dbg_assert_(VIDEO, writePos >= readPos);
while (OpcodeDecoder::CommandRunnable(availableBytes))
{
cpreg.status.CommandIdle = 0;
OpcodeDecoder::Run(availableBytes);
// if data was read by the opcode decoder then the video data pointer changed
readPos = g_pVideoData - &commandBuffer[0];
_dbg_assert_(VIDEO, writePos >= readPos);
availableBytes = writePos - readPos;
}
cpreg.status.CommandIdle = 1;
_dbg_assert_(VIDEO, writePos >= readPos);
bool ranDecoder = false;
// move data remaing in command buffer
if (readPos > 0)
{
memmove(&commandBuffer[0], &commandBuffer[readPos], availableBytes);
writePos -= readPos;
readPos = 0;
ranDecoder = true;
}
return ranDecoder;
}
} // end of namespace CommandProcessor

View File

@ -0,0 +1,153 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _COMMANDPROCESSOR_H_
#define _COMMANDPROCESSOR_H_
#include "Common.h"
#include "pluginspecs_video.h"
class PointerWrap;
namespace CommandProcessor
{
// internal hardware addresses
enum
{
STATUS_REGISTER = 0x00,
CTRL_REGISTER = 0x02,
CLEAR_REGISTER = 0x04,
FIFO_TOKEN_REGISTER = 0x0E,
FIFO_BOUNDING_BOX_LEFT = 0x10,
FIFO_BOUNDING_BOX_RIGHT = 0x12,
FIFO_BOUNDING_BOX_TOP = 0x14,
FIFO_BOUNDING_BOX_BOTTOM = 0x16,
FIFO_BASE_LO = 0x20,
FIFO_BASE_HI = 0x22,
FIFO_END_LO = 0x24,
FIFO_END_HI = 0x26,
FIFO_HI_WATERMARK_LO = 0x28,
FIFO_HI_WATERMARK_HI = 0x2a,
FIFO_LO_WATERMARK_LO = 0x2c,
FIFO_LO_WATERMARK_HI = 0x2e,
FIFO_RW_DISTANCE_LO = 0x30,
FIFO_RW_DISTANCE_HI = 0x32,
FIFO_WRITE_POINTER_LO = 0x34,
FIFO_WRITE_POINTER_HI = 0x36,
FIFO_READ_POINTER_LO = 0x38,
FIFO_READ_POINTER_HI = 0x3A,
FIFO_BP_LO = 0x3C,
FIFO_BP_HI = 0x3E
};
// Fifo Status Register
union UCPStatusReg
{
struct
{
unsigned OverflowHiWatermark : 1;
unsigned UnderflowLoWatermark : 1;
unsigned ReadIdle : 1; // done reading
unsigned CommandIdle : 1; // done processing commands
unsigned Breakpoint : 1;
unsigned : 11;
};
u16 Hex;
UCPStatusReg() {Hex = 0; }
UCPStatusReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPCtrlReg
{
struct
{
unsigned GPReadEnable : 1;
unsigned CPIntEnable : 1;
unsigned FifoOverflowIntEnable : 1;
unsigned FifoUnderflowIntEnable : 1;
unsigned GPLinkEnable : 1;
unsigned BPEnable : 1;
unsigned : 10;
};
u16 Hex;
UCPCtrlReg() {Hex = 0; }
UCPCtrlReg(u16 _hex) {Hex = _hex; }
};
// Fifo Control Register
union UCPClearReg
{
struct
{
unsigned ClearFifoOverflow : 1;
unsigned ClearFifoUnderflow : 1;
unsigned ClearMetrices : 1;
unsigned : 13;
};
u16 Hex;
UCPClearReg() {Hex = 0; }
UCPClearReg(u16 _hex) {Hex = _hex; }
};
struct CPReg
{
UCPStatusReg status; // 0x00
UCPCtrlReg ctrl; // 0x02
UCPClearReg clear; // 0x04
u32 unk0; // 0x06
u32 unk1; // 0x0a
u16 token; // 0x0e
u16 bboxleft; // 0x10
u16 bboxtop; // 0x12
u16 bboxright; // 0x14
u16 bboxbottom; // 0x16
u16 unk2; // 0x18
u32 fifobase; // 0x20
u32 fifoend; // 0x24
u32 hiwatermark; // 0x28
u32 lowatermark; // 0x2c
u32 rwdistance; // 0x30
u32 writeptr; // 0x34
u32 readptr; // 0x38
u32 breakpt; // 0x3c
};
extern CPReg cpreg;
// Init
void Init();
void Shutdown();
void DoState(PointerWrap &p);
bool RunBuffer();
// Read
void Read16(u16& _rReturnValue, const u32 _Address);
void Write16(const u16 _Data, const u32 _Address);
void Read32(u32& _rReturnValue, const u32 _Address);
void Write32(const u32 _Data, const u32 _Address);
// for CGPFIFO
void GatherPipeBursted();
void UpdateInterrupts();
void UpdateInterruptsFromVideoPlugin();
} // end of namespace CommandProcessor
#endif

View File

@ -0,0 +1,177 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "main.h"
#include "DebugUtil.h"
#include "BPMemLoader.h"
#include "TextureSampler.h"
#include "VideoConfig.h"
#include "EfbInterface.h"
#include "Statistics.h"
#include "HwRasterizer.h"
#include "StringUtil.h"
#include "../../../Core/VideoCommon/Src/ImageWrite.h"
namespace DebugUtil
{
u32 skipFrames = 0;
bool SaveTexture(const char* filename, u32 texmap, int width, int height)
{
u8 *data = new u8[width * height * 4];
GetTextureBGRA(data, texmap, width, height);
bool result = SaveTGA(filename, width, height, data);
delete []data;
return result;
}
void SaveTexture(const char* filename, u32 texmap)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
u8 subTexmap = texmap & 3;
TexImage0& ti0 = texUnit.texImage0[subTexmap];
SaveTexture(filename, texmap, ti0.width, ti0.height);
}
void GetTextureBGRA(u8 *dst, u32 texmap, int width, int height)
{
u8 sample[4];
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++) {
TextureSampler::Sample((float)x, (float)y, 0, texmap, sample);
// rgba to bgra
*(dst++) = sample[2];
*(dst++) = sample[1];
*(dst++) = sample[0];
*(dst++) = sample[3];
}
}
void DumpActiveTextures()
{
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
{
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
SaveTexture(StringFromFormat("%s/tar%i_ind%i_map%i.tga", FULL_DUMP_TEXTURES_DIR, stats.thisFrame.numDrawnObjects, stageNum, texmap).c_str(), texmap);
}
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);
SaveTexture(StringFromFormat("%s/tar%i_stage%i_map%i.tga", FULL_DUMP_TEXTURES_DIR, stats.thisFrame.numDrawnObjects, stageNum, texmap).c_str(), texmap);
}
}
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);
// rgba to bgra
*(writePtr++) = sample[2];
*(writePtr++) = sample[1];
*(writePtr++) = sample[0];
*(writePtr++) = sample[3];
}
bool result = 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;
}
bool result = SaveTGA(filename, EFB_WIDTH, EFB_HEIGHT, data);
delete []data;
}
void OnObjectBegin()
{
if (!g_SkipFrame)
{
if (g_Config.bDumpTextures)
DumpActiveTextures();
if (g_Config.bHwRasterizer)
HwRasterizer::BeginTriangles();
}
}
void OnObjectEnd()
{
if (!g_SkipFrame)
{
if (g_Config.bDumpObjects)
DumpEfb(StringFromFormat("%s/object%i.tga", FULL_FRAMES_DIR, stats.thisFrame.numDrawnObjects).c_str());
if (g_Config.bHwRasterizer)
HwRasterizer::EndTriangles();
stats.thisFrame.numDrawnObjects++;
}
}
void OnFrameEnd()
{
if (!g_SkipFrame)
{
if (g_Config.bDumpFrames)
{
DumpEfb(StringFromFormat("%s/frame%i_color.tga", FULL_FRAMES_DIR, stats.frameCount).c_str());
DumpDepth(StringFromFormat("%s/frame%i_depth.tga", FULL_FRAMES_DIR, stats.frameCount).c_str());
}
}
g_SkipFrame = skipFrames > 0;
skipFrames = g_SkipFrame?(skipFrames-1):g_Config.nFrameSkip;
}
}

View File

@ -0,0 +1,33 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DEBUGUTIL_H
#define _DEBUGUTIL_H
namespace DebugUtil
{
void GetTextureBGRA(u8 *dst, u32 texmap, int width, int height);
void DumpActiveTextures();
void OnObjectBegin();
void OnObjectEnd();
void OnFrameEnd();
}
#endif

View File

@ -0,0 +1,99 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "main.h"
#include "BPMemLoader.h"
#include "EfbCopy.h"
#include "EfbInterface.h"
#include "Renderer.h"
#include "TextureEncoder.h"
#include "Statistics.h"
#include "VideoConfig.h"
#include "DebugUtil.h"
#include "HwRasterizer.h"
namespace EfbCopy
{
void CopyToXfb()
{
if (!g_Config.bHwRasterizer)
{
// copy to open gl for rendering
EfbInterface::UpdateColorTexture();
Renderer::DrawTexture(EfbInterface::efbColorTexture, EFB_WIDTH, EFB_HEIGHT);
}
Renderer::SwapBuffer();
}
void CopyToRam()
{
u8 *dest_ptr = g_VideoInitialize.pGetMemoryPointer(bpmem.copyTexDest << 5);
TextureEncoder::Encode(dest_ptr);
}
void ClearEfb()
{
u32 clearColor = (bpmem.clearcolorAR & 0xff) | Common::swap16(bpmem.clearcolorGB) << 8 | (bpmem.clearcolorAR & 0xff00) << 16;
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_SkipFrame)
{
if (bpmem.triggerEFBCopy.copy_to_xfb)
{
CopyToXfb();
g_VideoInitialize.pCopiedToXFB(false);
stats.frameCount++;
}
else
{
CopyToRam();
}
if (bpmem.triggerEFBCopy.clear)
{
if (g_Config.bHwRasterizer)
HwRasterizer::Clear();
else
ClearEfb();
}
}
}
}

View File

@ -0,0 +1,32 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _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

View File

@ -0,0 +1,545 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "EfbInterface.h"
#include "BPMemLoader.h"
#include "../../../Core/VideoCommon/Src/LookUpTables.h"
#include "PixelEngine.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 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 & 0xff03ffff;
val |= (a32 << 16) & 0xfc0000;
*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 & 0x00ffffff;
*dst = val;
}
break;
case PIXELFMT_RGBA6_Z24:
{
u32 src = *(u32*)rgb;
u32 *dst = (u32*)&efb[offset];
u32 val = *dst & 0xfffc0000;
val |= (src >> 2) & 0x3f;
val |= (src >> 4) & 0xfc0;
val |= (src >> 6) & 0x3f000;
*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 & 0x00ffffff;
*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 & 0x00ffffff;
*dst = val;
}
break;
case PIXELFMT_RGBA6_Z24:
{
u32 src = *(u32*)color;
u32 *dst = (u32*)&efb[offset];
u32 val = *dst & 0xff000000;
val |= (src >> 2) & 0x3f;
val |= (src >> 4) & 0xfc0;
val |= (src >> 6) & 0x3f000;
val |= (src >> 8) & 0xfc0000;
*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 & 0x00ffffff;
*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 = 0xff000000 | (src & 0x00ffffff);
*dst = val;
}
break;
case PIXELFMT_RGBA6_Z24:
{
u32 src = *(u32*)&efb[offset];
color[0] = Convert6To8(src & 0x3f);
color[1] = Convert6To8((src >> 6) & 0x3f);
color[2] = Convert6To8((src >> 12) & 0x3f);
color[3] = 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 = 0xff000000 | (src & 0x00ffffff);
*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[3];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 5: // invsrcalpha
{
u8 alpha = 0xff - srcClr[3];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 6: // dstalpha
{
u8 alpha = dstClr[3];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 7: // invdstalpha
{
u8 alpha = 0xff - dstClr[3];
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[3];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 5: // invsrcalpha
{
u8 alpha = 0xff - srcClr[3];
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 6: // dstalpha
{
u8 alpha = dstClr[3] & 0xff;
u32 factor = alpha << 24 | alpha << 16 | alpha << 8 | alpha;
return factor;
}
case 7: // invdstalpha
{
u8 alpha = 0xff - dstClr[3];
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
dstClr = dstClr;
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[3] = 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[3]);
// branchless bounding box update
PixelEngine::pereg.boxLeft = PixelEngine::pereg.boxLeft>x?x:PixelEngine::pereg.boxLeft;
PixelEngine::pereg.boxRight = PixelEngine::pereg.boxRight<x?x:PixelEngine::pereg.boxRight;
PixelEngine::pereg.boxTop = PixelEngine::pereg.boxTop>y?y:PixelEngine::pereg.boxTop;
PixelEngine::pereg.boxBottom = PixelEngine::pereg.boxBottom<y?y:PixelEngine::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[3]);
}
void SetDepth(u16 x, u16 y, u32 depth)
{
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++] = color;
}
}
}
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;
}
}

View File

@ -0,0 +1,50 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _EFB_INTERFACE_H_
#define _EFB_INTERFACE_H_
#include "VideoCommon.h"
namespace EfbInterface
{
const int DEPTH_BUFFER_START = EFB_WIDTH * EFB_HEIGHT * 3;
// color order is RGBA
// 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
}
#endif

View File

@ -0,0 +1,754 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "main.h"
#include "VideoConfig.h"
#include "IniFile.h"
#include "svnrev.h"
#include "Setup.h"
//#include "Render.h"
#if defined(_WIN32)
#include "Win32.h"
#else
struct RECT
{
int left, top;
int right, bottom;
};
#endif
#include "GLUtil.h"
// Handles OpenGL and the window
// Window dimensions.
static int s_backbuffer_width;
static int s_backbuffer_height;
#ifndef _WIN32
GLWindow GLWin;
#endif
#if defined(_WIN32)
static HDC hDC = NULL; // Private GDI Device Context
static HGLRC hRC = NULL; // Permanent Rendering Context
extern HINSTANCE g_hInstance;
#endif
void OpenGL_SwapBuffers()
{
#if USE_SDL
SDL_GL_SwapBuffers();
#elif defined(HAVE_COCOA) && HAVE_COCOA
cocoaGLSwap(GLWin.cocoaCtx,GLWin.cocoaWin);
#elif defined(_WIN32)
SwapBuffers(hDC);
#elif defined(USE_WX) && USE_WX
GLWin.glCanvas->SwapBuffers();
#elif defined(HAVE_X11) && HAVE_X11
glXSwapBuffers(GLWin.dpy, GLWin.win);
#endif
}
u32 OpenGL_GetBackbufferWidth()
{
return s_backbuffer_width;
}
u32 OpenGL_GetBackbufferHeight()
{
return s_backbuffer_height;
}
void OpenGL_SetWindowText(const char *text)
{
#if USE_SDL
SDL_WM_SetCaption(text, NULL);
#elif defined(HAVE_COCOA) && HAVE_COCOA
cocoaGLSetTitle(GLWin.cocoaWin, text);
#elif defined(_WIN32)
// TODO convert text to unicode and change SetWindowTextA to SetWindowText
SetWindowTextA(EmuWindow::GetWnd(), text);
#elif defined(USE_WX) && USE_WX
GLWin.frame->SetTitle(wxString::FromAscii(text));
#elif defined(HAVE_X11) && HAVE_X11 // GLX
/**
* Tell X to ask the window manager to set the window title. (X
* itself doesn't provide window title functionality.)
*/
XStoreName(GLWin.dpy, GLWin.win, text);
#endif
}
// =======================================================================================
// Draw messages on top of the screen
// ------------------
unsigned int Callback_PeekMessages()
{
#ifdef _WIN32
// TODO: peekmessage
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
#else
return FALSE;
#endif
}
// Show the current FPS
void UpdateFPSDisplay(const char *text)
{
char temp[512];
sprintf(temp, "SVN R%s: SW: %s", SVN_REV_STR, text);
OpenGL_SetWindowText(temp);
}
// =========================
// =======================================================================================
// Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
// ------------------
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _twidth, int _theight)
{
#if defined(_WIN32)
EmuWindow::SetSize(_twidth, _theight);
#endif
// ----------------------------
// ---------------------------------------------------------------------------------------
// Control window size and picture scaling
// ------------------
s_backbuffer_width = _twidth;
s_backbuffer_height = _theight;
g_VideoInitialize.pPeekMessages = &Callback_PeekMessages;
g_VideoInitialize.pUpdateFPSDisplay = &UpdateFPSDisplay;
#if USE_SDL
//init sdl video
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
//TODO : Display an error message
SDL_Quit();
return false;
}
//setup ogl to use double buffering
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#elif defined(HAVE_COCOA) && HAVE_COCOA
GLWin.width = s_backbuffer_width;
GLWin.height = s_backbuffer_height;
GLWin.cocoaWin = cocoaGLCreateWindow(GLWin.width, GLWin.height);
GLWin.cocoaCtx = cocoaGLInit(g_Config.iMultisampleMode);
#elif defined(USE_WX) && USE_WX
int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
wxSize size(_iwidth, _iheight);
if (!g_Config.renderToMainframe ||
g_VideoInitialize.pWindowHandle == NULL) {
GLWin.frame = new wxFrame((wxWindow *)g_VideoInitialize.pWindowHandle,
-1, _("Dolphin"), wxPoint(50,50), size);
} else {
GLWin.frame = new wxFrame((wxWindow *)NULL,
-1, _("Dolphin"), wxPoint(50,50), size);
}
#if defined(__APPLE__)
GLWin.glCanvas = new wxGLCanvas(GLWin.frame, wxID_ANY, wxPoint(0,0), size, 0, wxT("Dolphin"), args, wxNullPalette);
#else
GLWin.glCanvas = new wxGLCanvas(GLWin.frame, wxID_ANY, args,
wxPoint(0,0), size, wxSUNKEN_BORDER);
GLWin.glCtxt = new wxGLContext(GLWin.glCanvas);
#endif
GLWin.frame->Show(TRUE);
GLWin.glCanvas->Show(TRUE);
#if defined(__APPLE__)
GLWin.glCanvas->SetCurrent();
#else
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
// GLWin.glCtxt->SetCurrent(*GLWin.glCanvas);
#endif
#elif defined(_WIN32)
// ---------------------------------------------------------------------------------------
// Create rendering window in Windows
// ----------------------
// Create a separate window
if (!g_Config.renderToMainframe || g_VideoInitialize.pWindowHandle == NULL)
g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create(NULL, g_hInstance, _T("Please wait..."));
// Create a child window
else
g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create((HWND)g_VideoInitialize.pWindowHandle, g_hInstance, _T("Please wait..."));
// Show the window
EmuWindow::Show();
if (g_VideoInitialize.pWindowHandle == NULL)
{
g_VideoInitialize.pSysMessage("failed to create window");
return false;
}
GLuint PixelFormat; // Holds The Results After Searching For A Match
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT rcdesktop;
GetWindowRect(GetDesktopWindow(), &rcdesktop);
if (g_Config.bFullscreen) {
//s_backbuffer_width = rcdesktop.right - rcdesktop.left;
//s_backbuffer_height = rcdesktop.bottom - rcdesktop.top;
DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = s_backbuffer_width;
dmScreenSettings.dmPelsHeight = s_backbuffer_height;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL,_T("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?"),_T("NeHe GL"),MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
g_Config.bFullscreen = false;
else
return false;
}
}
else
{
// Change to default resolution
ChangeDisplaySettings(NULL, 0);
}
if (g_Config.bFullscreen && !g_Config.renderToMainframe)
{
// Hide the cursor
ShowCursor(FALSE);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
RECT rc = {0, 0, s_backbuffer_width, s_backbuffer_height};
AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// EmuWindow::GetWnd() is either the new child window or the new separate window
if (g_Config.bFullscreen)
// We put the window at the upper left corner of the screen, so x = y = 0
SetWindowPos(EmuWindow::GetWnd(), NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION | SWP_NOZORDER);
else
SetWindowPos(EmuWindow::GetWnd(), NULL, X, Y, rc.right-rc.left, rc.bottom-rc.top, SWP_NOREPOSITION | SWP_NOZORDER);
PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
32, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // 8bit Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
24, // 24Bit Z-Buffer (Depth Buffer)
8, // 8bit Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if (!(hDC=GetDC(EmuWindow::GetWnd()))) {
PanicAlert("(1) Can't create an OpenGL Device context. Fail.");
return false;
}
if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) {
PanicAlert("(2) Can't find a suitable PixelFormat.");
return false;
}
if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {
PanicAlert("(3) Can't set the PixelFormat.");
return false;
}
if (!(hRC = wglCreateContext(hDC))) {
PanicAlert("(4) Can't create an OpenGL rendering context.");
return false;
}
// --------------------------------------
#elif defined(HAVE_X11) && HAVE_X11
XVisualInfo *vi;
Colormap cmap;
int dpyWidth, dpyHeight;
int glxMajorVersion, glxMinorVersion;
int vidModeMajorVersion, vidModeMinorVersion;
Atom wmDelete;
// attributes for a single buffered visual in RGBA format with at least
// 8 bits per color and a 24 bit depth buffer
int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 24,
None};
// attributes for a double buffered visual in RGBA format with at least
// 8 bits per color and a 24 bit depth buffer
int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode, GLX_SAMPLES_ARB, 1, None };
GLWin.dpy = XOpenDisplay(0);
g_VideoInitialize.pWindowHandle = (HWND)GLWin.dpy;
GLWin.screen = DefaultScreen(GLWin.dpy);
// Fullscreen option.
GLWin.fs = g_Config.bFullscreen; //Set to setting in Options
/* get an appropriate visual */
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
if (vi == NULL) {
vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
GLWin.doubleBuffered = False;
ERROR_LOG(VIDEO, "Only Singlebuffered Visual!");
}
else {
GLWin.doubleBuffered = True;
NOTICE_LOG(VIDEO, "Got Doublebuffered Visual!");
}
glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion);
NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion);
// Create a GLX context.
GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE);
if(!GLWin.ctx)
{
PanicAlert("Couldn't Create GLX context.Quit");
exit(0); // TODO: Don't bring down entire Emu
}
// Create a color map.
cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen), vi->visual, AllocNone);
GLWin.attr.colormap = cmap;
GLWin.attr.border_pixel = 0;
XkbSetDetectableAutoRepeat(GLWin.dpy, True, NULL);
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
// get a connection
XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion);
if (GLWin.fs) {
XF86VidModeModeInfo **modes = NULL;
int modeNum = 0;
int bestMode = 0;
// set best mode to current
bestMode = 0;
NOTICE_LOG(VIDEO, "XF86VidModeExtension-Version %d.%d", vidModeMajorVersion, vidModeMinorVersion);
XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes);
if (modeNum > 0 && modes != NULL) {
/* save desktop-resolution before switching modes */
GLWin.deskMode = *modes[0];
/* look for mode with requested resolution */
for (int i = 0; i < modeNum; i++) {
if ((modes[i]->hdisplay == _twidth) && (modes[i]->vdisplay == _theight)) {
bestMode = i;
}
}
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]);
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
dpyWidth = modes[bestMode]->hdisplay;
dpyHeight = modes[bestMode]->vdisplay;
NOTICE_LOG(VIDEO, "Resolution %dx%d", dpyWidth, dpyHeight);
XFree(modes);
/* create a fullscreen window */
GLWin.attr.override_redirect = True;
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask;
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
&GLWin.attr);
XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0);
XMapRaised(GLWin.dpy, GLWin.win);
XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask,
GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
}
else {
ERROR_LOG(VIDEO, "Failed to start fullscreen. If you received the "
"\"XFree86-VidModeExtension\" extension is missing, add\n"
"Load \"extmod\"\n"
"to your X configuration file (under the Module Section)\n");
GLWin.fs = 0;
}
}
#endif
if (!GLWin.fs) {
//XRootWindow(dpy,screen)
//int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
//int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// create a window in window mode
GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask |
StructureNotifyMask | ResizeRedirectMask;
GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
0, 0, _twidth, _theight, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr);
// only set window title and handle wm_delete_events if in windowed mode
wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1);
XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU",
"GPU", None, NULL, 0, NULL);
XMapRaised(GLWin.dpy, GLWin.win);
}
#endif
return true;
}
bool OpenGL_MakeCurrent()
{
#if USE_SDL
// Note: The reason for having the call to SDL_SetVideoMode in here instead
// of in OpenGL_Create() is that "make current" is part of the video
// mode setting and is not available as a separate call in SDL. We
// have to do "make current" here because this method runs in the CPU
// thread while OpenGL_Create() runs in a diferent thread and "make
// current" has to be done in the same thread that will be making
// calls to OpenGL.
// Fetch video info.
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
if (!videoInfo) {
// TODO: Display an error message.
SDL_Quit();
return false;
}
// Compute video mode flags.
const int videoFlags = SDL_OPENGL
| ( videoInfo->hw_available ? SDL_HWSURFACE : SDL_SWSURFACE )
| ( g_Config.bFullscreen ? SDL_FULLSCREEN : 0);
// Set vide mode.
// TODO: Can we use this field or is a separate field needed?
int _twidth = s_backbuffer_width;
int _theight = s_backbuffer_height;
SDL_Surface *screen = SDL_SetVideoMode(_twidth, _theight, 0, videoFlags);
if (!screen) {
//TODO : Display an error message
SDL_Quit();
return false;
}
#elif defined(HAVE_COCOA) && HAVE_COCOA
cocoaGLMakeCurrent(GLWin.cocoaCtx,GLWin.cocoaWin);
#elif defined(_WIN32)
if (!wglMakeCurrent(hDC,hRC)) {
PanicAlert("(5) Can't Activate The GL Rendering Context.");
return false;
}
#elif defined(USE_WX) && USE_WX
#if defined(__APPLE__)
GLWin.glCanvas->SetCurrent();
#else
GLWin.glCanvas->SetCurrent(*GLWin.glCtxt);
#endif
return true;
#elif defined(HAVE_X11) && HAVE_X11
Window winDummy;
unsigned int borderDummy;
// connect the glx-context to the window
glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
NOTICE_LOG(VIDEO, "GLWin Depth %d", GLWin.depth)
if (glXIsDirect(GLWin.dpy, GLWin.ctx)) {
NOTICE_LOG(VIDEO, "detected direct rendering");
} else {
ERROR_LOG(VIDEO, "no Direct Rendering possible!");
}
// better for pad plugin key input (thc)
XSelectInput(GLWin.dpy, GLWin.win, ExposureMask | KeyPressMask | ButtonPressMask | KeyReleaseMask | ButtonReleaseMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask |
FocusChangeMask );
#endif
return true;
}
// =======================================================================================
// Update window width, size and etc. Called from Render.cpp
// ----------------
void OpenGL_Update()
{
#if USE_SDL
SDL_Surface *surface = SDL_GetVideoSurface();
RECT rcWindow = {0};
if (!surface)
return;
s_backbuffer_width = surface->w;
s_backbuffer_height = surface->h;
rcWindow.right = surface->w;
rcWindow.bottom = surface->h;
#elif defined(HAVE_COCOA) && HAVE_COCOA
RECT rcWindow = {0};
rcWindow.right = GLWin.width;
rcWindow.bottom = GLWin.height;
#elif defined(USE_WX) && USE_WX
RECT rcWindow = {0};
rcWindow.right = GLWin.width;
rcWindow.bottom = GLWin.height;
// TODO fill in
#elif defined(_WIN32)
RECT rcWindow;
if (!EmuWindow::GetParentWnd())
{
// We are not rendering to a child window - use client size.
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
}
else
{
// We are rendering to a child window - use parent size.
GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow);
}
// ---------------------------------------------------------------------------------------
// Get the new window width and height
// ------------------
// See below for documentation
// ------------------
int width = rcWindow.right - rcWindow.left;
int height = rcWindow.bottom - rcWindow.top;
// If we are rendering to a child window
if (EmuWindow::GetParentWnd() != 0)
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
s_backbuffer_width = width;
s_backbuffer_height = height;
#elif defined(HAVE_X11) && HAVE_X11
// We just check all of our events here
XEvent event;
KeySym key;
static RECT rcWindow;
static bool ShiftPressed = false;
static bool ControlPressed = false;
static int FKeyPressed = -1;
int num_events;
for (num_events = XPending(GLWin.dpy);num_events > 0;num_events--) {
XNextEvent(GLWin.dpy, &event);
switch(event.type) {
case KeyRelease:
key = XLookupKeysym((XKeyEvent*)&event, 0);
if(key >= XK_F1 && key <= XK_F9) {
g_VideoInitialize.pKeyPress(FKeyPressed, ShiftPressed, ControlPressed);
FKeyPressed = -1;
} else {
if(key == XK_Shift_L || key == XK_Shift_R)
ShiftPressed = false;
else if(key == XK_Control_L || key == XK_Control_R)
ControlPressed = false;
else
XPutBackEvent(GLWin.dpy, &event);
}
break;
case KeyPress:
key = XLookupKeysym((XKeyEvent*)&event, 0);
if(key >= XK_F1 && key <= XK_F9)
FKeyPressed = key - 0xff4e;
else {
if(key == XK_Shift_L || key == XK_Shift_R)
ShiftPressed = true;
else if(key == XK_Control_L || key == XK_Control_R)
ControlPressed = true;
else
XPutBackEvent(GLWin.dpy, &event);
}
break;
case ButtonPress:
case ButtonRelease:
XPutBackEvent(GLWin.dpy, &event);
break;
case ConfigureNotify:
Window winDummy;
unsigned int borderDummy;
XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y,
&GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);
s_backbuffer_width = GLWin.width;
s_backbuffer_height = GLWin.height;
rcWindow.left = 0;
rcWindow.top = 0;
rcWindow.right = GLWin.width;
rcWindow.bottom = GLWin.height;
break;
case ClientMessage: //TODO: We aren't reading this correctly, It could be anything, highest chance is that it's a close event though
Shutdown(); // Calling from here since returning false does nothing
return;
break;
default:
//TODO: Should we put the event back if we don't handle it?
// I think we handle all the needed ones, the rest shouldn't matter
// But to be safe, let's but them back anyway
//XPutBackEvent(GLWin.dpy, &event);
break;
}
}
return;
#endif
}
// =======================================================================================
// Close plugin
// ----------------
void OpenGL_Shutdown()
{
#if USE_SDL
SDL_Quit();
#elif defined(HAVE_COCOA) && HAVE_COCOA
cocoaGLDelete(GLWin.cocoaCtx);
#elif defined(USE_WX) && USE_WX
delete GLWin.glCanvas;
delete GLWin.frame;
#elif defined(_WIN32)
if (hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
// [F|RES]: if this fails i dont see the message box and
// cant get out of the modal state so i disable it.
// This function fails only if i render to main window
// MessageBox(NULL,"Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
{
ERROR_LOG(VIDEO, "Release Rendering Context Failed.");
}
hRC = NULL; // Set RC To NULL
}
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC
{
#ifndef SETUP_TIMER_WAITING // This fails
ERROR_LOG(VIDEO, "Release Device Context Failed.");
#endif
hDC = NULL; // Set DC To NULL
}
#elif defined(HAVE_X11) && HAVE_X11
if (GLWin.ctx)
{
if (!glXMakeCurrent(GLWin.dpy, None, NULL))
{
ERROR_LOG(VIDEO, "Could not release drawing context.\n");
}
XUnmapWindow(GLWin.dpy, GLWin.win);
glXDestroyContext(GLWin.dpy, GLWin.ctx);
XCloseDisplay(GLWin.dpy);
GLWin.ctx = NULL;
}
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
/* switch back to original desktop resolution if we were in fs */
if (GLWin.dpy != NULL) {
if (GLWin.fs) {
XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
}
}
#endif
#endif
}
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line)
{
GLint err = glGetError();
if (err != GL_NO_ERROR)
{
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n", file, line, function, err, gluErrorString(err));
}
return err;
}
void OpenGL_ReportARBProgramError()
{
const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
if (pstr != NULL && pstr[0] != 0)
{
GLint loc = 0;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
ERROR_LOG(VIDEO, "program error at %d: ", loc);
ERROR_LOG(VIDEO, (char*)pstr);
ERROR_LOG(VIDEO, "");
}
}
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
{
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
const char *error = "-";
switch (fbo_status)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error = "INCOMPLETE_ATTACHMENT_EXT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error = "INCOMPLETE_MISSING_ATTACHMENT_EXT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error = "INCOMPLETE_DIMENSIONS_EXT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error = "INCOMPLETE_FORMATS_EXT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error = "INCOMPLETE_DRAW_BUFFER_EXT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error = "INCOMPLETE_READ_BUFFER_EXT"; break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error = "UNSUPPORTED_EXT"; break;
}
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n", file, line, function, error);
return false;
}
return true;
}

View File

@ -0,0 +1,155 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _GLINIT_H_
#define _GLINIT_H_
#if defined GLTEST && GLTEST
#include "nGLUtil.h"
#else
#include "Common.h"
#include <string>
#include "VideoConfig.h"
#include "pluginspecs_video.h"
#ifdef _WIN32
#define GLEW_STATIC
#include <GLew/glew.h>
#include <GLew/wglew.h>
#include <GLew/gl.h>
#include <GLew/glext.h>
#else // linux basic definitions
#if defined(USE_WX) && USE_WX
#include <GL/glew.h>
#include "wx/wx.h"
#include "wx/glcanvas.h"
#undef HAVE_X11
#elif defined(HAVE_X11) && HAVE_X11
#define I_NEED_OS2_H // HAXXOR
#include <GL/glxew.h>
#include <X11/XKBlib.h>
#elif defined(USE_SDL) && USE_SDL
#include <GL/glew.h>
#include <SDL.h>
#elif defined(HAVE_COCOA) && HAVE_COCOA
#include <GL/glew.h>
#include "cocoaGL.h"
#endif // end USE_WX
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#endif // linux basic definitions
#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils
#define GL_DEPTH_STENCIL_EXT 0x84F9
#define GL_UNSIGNED_INT_24_8_EXT 0x84FA
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1
#endif
#ifndef _WIN32
#if defined(HAVE_X11) && HAVE_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
#include <X11/extensions/xf86vmode.h>
#endif // XXF86VM
#endif // X11
#include <sys/stat.h>
#include <sys/types.h>
typedef struct {
int screen;
#if defined(HAVE_COCOA) && HAVE_COCOA
NSWindow *cocoaWin;
NSOpenGLContext *cocoaCtx;
#elif defined(HAVE_X11) && HAVE_X11
Window win;
Display *dpy;
GLXContext ctx;
XSetWindowAttributes attr;
Bool fs;
Bool doubleBuffered;
#if defined(HAVE_XXF86VM) && HAVE_XXF86VM
XF86VidModeModeInfo deskMode;
#endif // XXF86VM
#endif // X11
#if defined(USE_WX) && USE_WX
wxGLCanvas *glCanvas;
wxFrame *frame;
wxGLContext *glCtxt;
#endif
int x, y;
unsigned int width, height;
unsigned int depth;
} GLWindow;
extern GLWindow GLWin;
#endif
// Public OpenGL util
// Initialization / upkeep
bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height);
void OpenGL_Shutdown();
void OpenGL_Update();
bool OpenGL_MakeCurrent();
void OpenGL_SwapBuffers();
// Get status
u32 OpenGL_GetBackbufferWidth();
u32 OpenGL_GetBackbufferHeight();
// Set things
void OpenGL_SetWindowText(const char *text);
// Error reporting - use the convenient macros.
void OpenGL_ReportARBProgramError();
GLuint OpenGL_ReportGLError(const char *function, const char *file, int line);
bool OpenGL_ReportFBOError(const char *function, const char *file, int line);
#if 1
#define GL_REPORT_ERROR() OpenGL_ReportGLError (__FUNCTION__, __FILE__, __LINE__)
#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError()
#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError (__FUNCTION__, __FILE__, __LINE__)
#else
#define GL_REPORT_ERROR() GL_NO_ERROR
#define GL_REPORT_PROGRAM_ERROR()
#define GL_REPORT_FBO_ERROR()
#endif
#if defined(_DEBUG) || defined(DEBUGFAST)
#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__)
#else
#define GL_REPORT_ERRORD() GL_NO_ERROR
#endif
#endif // GLTEST ??
#endif // _GLINIT_H_

View File

@ -0,0 +1,191 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "MemoryUtil.h"
#include <videocommon.h>
#include "BpMemLoader.h"
#include "HwRasterizer.h"
#include "GLUtil.h"
#include "NativeVertexFormat.h"
#include "DebugUtil.h"
#define TEMP_SIZE (1024*1024*4)
namespace HwRasterizer
{
float efbHalfWidth;
float efbHalfHeight;
float texWidth;
float texHeight;
bool hasTexture;
u8 *temp;
void Init()
{
efbHalfWidth = EFB_WIDTH / 2.0f;
efbHalfHeight = 480 / 2.0f;
temp = (u8*)AllocateMemoryPages(TEMP_SIZE);
}
void LoadTexture()
{
FourTexUnits &texUnit = bpmem.tex[0];
u32 imageAddr = texUnit.texImage3[0].image_base;
TexCacheEntry &cacheEntry = textures[imageAddr];
cacheEntry.Update();
texWidth = (float)(bpmem.texcoords[0].s.scale_minus_1 + 1);
texHeight = (float)(bpmem.texcoords[0].t.scale_minus_1 + 1);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cacheEntry.texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, texUnit.texMode0[0].mag_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, (texUnit.texMode0[0].min_filter >= 4) ? GL_LINEAR : GL_NEAREST);
}
void BeginTriangles()
{
// disabling depth test sometimes allows more things to be visible
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
hasTexture = bpmem.tevorders[0].enable0;
if (hasTexture)
LoadTexture();
}
void EndTriangles()
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
}
void DrawColorVertex(OutputVertexData *v)
{
glColor3ub(v->color[0][0], v->color[0][1], v->color[0][2]);
glVertex3f(v->screenPosition[0] / efbHalfWidth - 1.0f, 1.0f - v->screenPosition[1] / efbHalfHeight, v->screenPosition[2]);
}
void DrawTextureVertex(OutputVertexData *v)
{
glTexCoord2f(v->texCoords[0][0] * texWidth, v->texCoords[0][1] * texHeight);
glVertex3f(v->screenPosition[0] / efbHalfWidth - 1.0f, 1.0f - v->screenPosition[1] / efbHalfHeight, v->screenPosition[2]);
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
glBegin(GL_TRIANGLES);
if (hasTexture)
{
DrawTextureVertex(v0);
DrawTextureVertex(v1);
DrawTextureVertex(v2);
}
else
{
DrawColorVertex(v0);
DrawColorVertex(v1);
DrawColorVertex(v2);
}
glEnd();
}
void Clear()
{
u8 r = (bpmem.clearcolorAR & 0x00ff);
u8 g = (bpmem.clearcolorGB & 0xff00) >> 8;
u8 b = (bpmem.clearcolorGB & 0x00ff);
u8 a = (bpmem.clearcolorAR & 0xff00) >> 8;
GLfloat left = (GLfloat)bpmem.copyTexSrcXY.x / efbHalfWidth - 1.0f;
GLfloat top = 1.0f - (GLfloat)bpmem.copyTexSrcXY.y / efbHalfHeight;
GLfloat right = (GLfloat)(left + bpmem.copyTexSrcWH.x + 1) / efbHalfWidth - 1.0f;
GLfloat bottom = 1.0f - (GLfloat)(top + bpmem.copyTexSrcWH.y + 1) / efbHalfHeight;
GLfloat depth = (GLfloat)bpmem.clearZValue / (GLfloat)0x00ffffff;
glBegin(GL_QUADS);
glColor4ub(r, g, b, a);
glVertex3f(left, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, top, depth);
glColor4ub(r, g, b, a);
glVertex3f(right, bottom, depth);
glColor4ub(r, g, b, a);
glVertex3f(left, bottom, depth);
glEnd();
}
TexCacheEntry::TexCacheEntry()
{
Create();
}
void TexCacheEntry::Create()
{
FourTexUnits &texUnit = bpmem.tex[0];
texImage0.hex = texUnit.texImage0[0].hex;
texImage1.hex = texUnit.texImage1[0].hex;
texImage2.hex = texUnit.texImage2[0].hex;
texImage3.hex = texUnit.texImage3[0].hex;
texTlut.hex = texUnit.texTlut[0].hex;
int width = texImage0.width;
int height = texImage0.height;
DebugUtil::GetTextureBGRA(temp, 0, width, height);
glGenTextures(1, (GLuint *)&texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
}
void TexCacheEntry::Destroy()
{
if (texture == 0)
return;
glDeleteTextures(1, &texture);
texture = 0;
}
void TexCacheEntry::Update()
{
FourTexUnits &texUnit = bpmem.tex[0];
// extra checks cause textures to be reloaded much more
if (texUnit.texImage0[0].hex != texImage0.hex ||
//texUnit.texImage1[0].hex != texImage1.hex ||
//texUnit.texImage2[0].hex != texImage2.hex ||
texUnit.texImage3[0].hex != texImage3.hex ||
texUnit.texTlut[0].hex != texTlut.hex)
{
Destroy();
Create();
}
}
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _HW_RASTERIZER_H
#define _HW_RASTERIZER_H
#include <map>
#include "BpMemLoader.h"
#include "GlUtil.h"
struct OutputVertexData;
namespace HwRasterizer
{
void Init();
void BeginTriangles();
void EndTriangles();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void Clear();
struct TexCacheEntry
{
TexImage0 texImage0;
TexImage1 texImage1;
TexImage2 texImage2;
TexImage3 texImage3;
TexTLUT texTlut;
GLuint texture;
TexCacheEntry();
void Create();
void Destroy();
void Update();
};
typedef std::map<u32, TexCacheEntry> TextureCache;
static TextureCache textures;
}
#endif

View File

@ -0,0 +1,83 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVEVERTEXFORMAT_H
#define _NATIVEVERTEXFORMAT_H
#define LOADERDECL __cdecl
typedef void (LOADERDECL *TPipelineFunction)();
struct InputVertexData
{
u8 posMtx;
u8 texMtx[8];
float position[4];
float normal[3][3];
u8 color[2][4];
float texCoords[8][2];
};
struct OutputVertexData
{
float mvPosition[3];
float projectedPosition[4];
float screenPosition[3];
float normal[3][3];
u8 color[2][4];
float texCoords[8][3];
void Lerp(float t, OutputVertexData *a, OutputVertexData *b)
{
#define LINTERP(T, OUT, IN) (OUT) + ((IN - OUT) * T)
#define LINTERP_INT(T, OUT, IN) (OUT) + (((IN - OUT) * T) >> 8)
for (int i = 0; i < 3; ++i)
mvPosition[i] = LINTERP(t, a->mvPosition[i], b->mvPosition[i]);
for (int i = 0; i < 4; ++i)
projectedPosition[i] = LINTERP(t, a->projectedPosition[i], b->projectedPosition[i]);
for (int i = 0; i < 3; ++i)
{
normal[i][0] = LINTERP(t, a->normal[i][0], b->normal[i][0]);
normal[i][1] = LINTERP(t, a->normal[i][1], b->normal[i][1]);
normal[i][2] = LINTERP(t, a->normal[i][2], b->normal[i][2]);
}
u16 t_int = (u16)(t * 256);
for (int i = 0; i < 4; ++i)
{
color[0][i] = LINTERP_INT(t_int, a->color[0][i], b->color[0][i]);
color[1][i] = LINTERP_INT(t_int, a->color[1][i], b->color[1][i]);
}
for (int i = 0; i < 8; ++i)
{
texCoords[i][0] = LINTERP(t, a->texCoords[i][0], b->texCoords[i][0]);
texCoords[i][1] = LINTERP(t, a->texCoords[i][1], b->texCoords[i][1]);
texCoords[i][2] = LINTERP(t, a->texCoords[i][2], b->texCoords[i][2]);
}
#undef LINTERP
#undef LINTERP_INT
}
};
#endif

View File

@ -0,0 +1,30 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _NATIVE_VERTEX_WRITER
#define _NATIVE_VERTEX_WRITER
// TODO: rename
namespace VertexManager
{
// TODO: move, rename.
extern u8* s_pCurBufferPointer;
}
#endif

View File

@ -0,0 +1,296 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
#include "main.h"
#include "OpcodeDecoder.h"
#include "BPMemLoader.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "VertexLoader.h"
#include "Statistics.h"
#include "DebugUtil.h"
typedef void (*DecodingFunction)(u32);
DecodingFunction currentFunction = NULL;
u32 minCommandSize;
u16 streamSize;
u16 streamAddress;
bool readOpcode;
VertexLoader vertexLoader;
bool inObjectStream;
u8 lastPrimCmd;
namespace OpcodeDecoder
{
void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
if(g_SkipFrame)
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
g_pVideoData += vertexSize;
iBufferSize -= vertexSize;
streamSize--;
}
}
else
{
while (streamSize > 0 && iBufferSize >= vertexSize)
{
vertexLoader.LoadVertex();
iBufferSize -= vertexSize;
streamSize--;
}
}
if (streamSize == 0)
{
// return to normal command processing
ResetDecoding();
}
}
void ReadXFData(u32 iBufferSize)
{
_assert_msg_(VIDEO, iBufferSize >= (u32)(streamSize * 4), "Underflow during standard opcode decoding");
u32 pData[16];
for (int i = 0; i < streamSize; i++)
pData[i] = DataReadU32();
LoadXFReg(streamSize, streamAddress, pData);
// return to normal command processing
ResetDecoding();
}
void ExecuteDisplayList(u32 addr, u32 count)
{
u8 *videoDataSave = g_pVideoData;
u8 *dlStart = g_VideoInitialize.pGetMemoryPointer(addr);
g_pVideoData = dlStart;
while (OpcodeDecoder::CommandRunnable(count))
{
OpcodeDecoder::Run(count);
// if data was read by the opcode decoder then the video data pointer changed
u32 readCount = g_pVideoData - dlStart;
dlStart = g_pVideoData;
_assert_msg_(VIDEO, count >= readCount, "Display list underrun");
count -= readCount;
}
g_pVideoData = videoDataSave;
}
void DecodeStandard(u32 bufferSize)
{
_assert_msg_(VIDEO, CommandRunnable(bufferSize), "Underflow during standard opcode decoding");
int Cmd = DataReadU8();
if (Cmd == GX_NOP)
return;
// check if switching in or out of an object
// only used for debuggging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
{
inObjectStream = false;
DebugUtil::OnObjectEnd();
}
if (Cmd & 0x80 && !inObjectStream)
{
inObjectStream = true;
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
switch(Cmd)
{
case GX_NOP:
break;
case GX_LOAD_CP_REG: //0x08
{
u32 SubCmd = DataReadU8();
u32 Value = DataReadU32();
LoadCPReg(SubCmd, Value);
}
break;
case GX_LOAD_XF_REG:
{
u32 Cmd2 = DataReadU32();
streamSize = ((Cmd2 >> 16) & 15) + 1;
streamAddress = Cmd2 & 0xFFFF;
currentFunction = ReadXFData;
minCommandSize = streamSize * 4;
readOpcode = false;
}
break;
case GX_LOAD_INDX_A: //used for position matrices
LoadIndexedXF(DataReadU32(), 0xC);
break;
case GX_LOAD_INDX_B: //used for normal matrices
LoadIndexedXF(DataReadU32(), 0xD);
break;
case GX_LOAD_INDX_C: //used for postmatrices
LoadIndexedXF(DataReadU32(), 0xE);
break;
case GX_LOAD_INDX_D: //used for lights
LoadIndexedXF(DataReadU32(), 0xF);
break;
case GX_CMD_CALL_DL:
{
u32 dwAddr = DataReadU32();
u32 dwCount = DataReadU32();
ExecuteDisplayList(dwAddr, dwCount);
}
break;
case 0x44:
// zelda 4 swords calls it and checks the metrics registers after that
break;
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
DEBUG_LOG(VIDEO, "Invalidate (vertex cache?)");
break;
case GX_LOAD_BP_REG: //0x61
{
u32 cmd = DataReadU32();
LoadBPReg(cmd);
}
break;
// draw primitives
default:
if (Cmd & 0x80)
{
u8 vatIndex = Cmd & GX_VAT_MASK;
u8 primitiveType = (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
vertexLoader.SetFormat(vatIndex, primitiveType);
// switch to primitive processing
streamSize = DataReadU16();
currentFunction = DecodePrimitiveStream;
minCommandSize = vertexLoader.GetVertexSize();
readOpcode = false;
INCSTAT(stats.thisFrame.numPrimatives);
DEBUG_LOG(VIDEO, "Draw begin");
}
else
{
PanicAlert("GFX: Unknown Opcode (0x%x).\n", Cmd);
break;
}
break;
}
}
void Init()
{
inObjectStream = false;
lastPrimCmd = 0;
ResetDecoding();
}
void ResetDecoding()
{
currentFunction = DecodeStandard;
minCommandSize = 1;
readOpcode = true;
}
bool CommandRunnable(u32 iBufferSize)
{
if (iBufferSize < minCommandSize)
return false;
if (readOpcode)
{
u8 Cmd = DataPeek8(0);
u32 minSize = 1;
switch(Cmd)
{
case GX_LOAD_CP_REG: //0x08
minSize = 6;
break;
case GX_LOAD_XF_REG:
minSize = 5;
break;
case GX_LOAD_INDX_A: //used for position matrices
minSize = 5;
break;
case GX_LOAD_INDX_B: //used for normal matrices
minSize = 5;
break;
case GX_LOAD_INDX_C: //used for postmatrices
minSize = 5;
break;
case GX_LOAD_INDX_D: //used for lights
minSize = 5;
break;
case GX_CMD_CALL_DL:
minSize = 9;
break;
case GX_LOAD_BP_REG: //0x61
minSize = 5;
break;
// draw primitives
default:
if (Cmd & 0x80)
minSize = 3;
break;
}
return (iBufferSize >= minSize);
}
return true;
}
void Run(u32 iBufferSize)
{
currentFunction(iBufferSize);
}
}

View File

@ -0,0 +1,62 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _OPCODEDECODER_H_
#define _OPCODEDECODER_H_
#include "pluginspecs_video.h"
namespace OpcodeDecoder
{
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x78
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
//these are defined 1/8th of their real values and without their top bit
#define GX_DRAW_QUADS 0x0 //0x80
#define GX_DRAW_TRIANGLES 0x2 //0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 //0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 //0xA0
#define GX_DRAW_LINES 0x5 //0xA8
#define GX_DRAW_LINE_STRIP 0x6 //0xB0
#define GX_DRAW_POINTS 0x7 //0xB8
void Init();
void ResetDecoding();
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
}
#endif

View File

@ -0,0 +1,176 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// http://developer.nvidia.com/object/General_FAQ.html#t6 !!!!!
#include "Common.h"
#include "ChunkFile.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
namespace PixelEngine
{
enum
{
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
INT_CAUSE_PE_FINISH = 0x400, // GP Finished
};
// STATE_TO_SAVE
PEReg PixelEngine::pereg;
static bool g_bSignalTokenInterrupt;
static bool g_bSignalFinishInterrupt;
static int et_SetTokenOnMainThread;
static int et_SetFinishOnMainThread;
void DoState(PointerWrap &p)
{
p.Do(pereg);
p.Do(g_bSignalTokenInterrupt);
p.Do(g_bSignalFinishInterrupt);
}
void UpdateInterrupts();
void SetToken_OnMainThread(u64 userdata, int cyclesLate);
void SetFinish_OnMainThread(u64 userdata, int cyclesLate);
void Init()
{
memset(&pereg, 0, sizeof(pereg));
et_SetTokenOnMainThread = false;
g_bSignalFinishInterrupt = false;
et_SetTokenOnMainThread = g_VideoInitialize.pRegisterEvent("SetToken", SetToken_OnMainThread);
et_SetFinishOnMainThread = g_VideoInitialize.pRegisterEvent("SetFinish", SetFinish_OnMainThread);
}
void Read16(u16& _uReturnValue, const u32 _iAddress)
{
DEBUG_LOG(PIXELENGINE, "(r16): 0x%08x", _iAddress);
u16 address = _iAddress & 0xFFF;
if (address <= 0x16)
_uReturnValue = ((u16*)&pereg)[address >> 1];
}
void Write32(const u32 _iValue, const u32 _iAddress)
{
WARN_LOG(PIXELENGINE, "(w32): 0x%08x @ 0x%08x",_iValue,_iAddress);
}
void Write16(const u16 _iValue, const u32 _iAddress)
{
u16 address = _iAddress & 0xFFF;
switch (address)
{
case PE_CTRL_REGISTER:
{
UPECtrlReg tmpCtrl(_iValue);
if (tmpCtrl.PEToken) g_bSignalTokenInterrupt = false;
if (tmpCtrl.PEFinish) g_bSignalFinishInterrupt = false;
pereg.ctrl.PETokenEnable = tmpCtrl.PETokenEnable;
pereg.ctrl.PEFinishEnable = tmpCtrl.PEFinishEnable;
pereg.ctrl.PEToken = 0; // this flag is write only
pereg.ctrl.PEFinish = 0; // this flag is write only
DEBUG_LOG(PIXELENGINE, "(w16): PE_CTRL_REGISTER: 0x%04x", _iValue);
UpdateInterrupts();
}
break;
default:
if (address <= 0x16)
((u16*)&pereg)[address >> 1] = _iValue;
break;
}
}
bool AllowIdleSkipping()
{
return !g_VideoInitialize.bUseDualCore || (!pereg.ctrl.PETokenEnable && !pereg.ctrl.PEFinishEnable);
}
void UpdateInterrupts()
{
// check if there is a token-interrupt
if (g_bSignalTokenInterrupt & pereg.ctrl.PETokenEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_TOKEN, false);
// check if there is a finish-interrupt
if (g_bSignalFinishInterrupt & pereg.ctrl.PEFinishEnable)
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, true);
else
g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, false);
}
// Called only if BPMEM_PE_TOKEN_INT_ID is ack by GP
void SetToken_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalTokenInterrupt = true;
//_dbg_assert_msg_(PIXELENGINE, (CommandProcessor::fifo.PEToken == (userdata&0xFFFF)), "WTF? BPMEM_PE_TOKEN_INT_ID's token != BPMEM_PE_TOKEN_ID's token" );
INFO_LOG(PIXELENGINE, "VIDEO Plugin raises INT_CAUSE_PE_TOKEN (btw, token: %04x)", pereg.token);
UpdateInterrupts();
}
void SetFinish_OnMainThread(u64 userdata, int cyclesLate)
{
g_bSignalFinishInterrupt = true;
UpdateInterrupts();
}
// SetToken
// THIS IS EXECUTED FROM VIDEO THREAD
void SetToken(const u16 _token, const int _bSetTokenAcknowledge)
{
pereg.token = _token;
if (_bSetTokenAcknowledge) // set token INT
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16));
}
else // set token value
{
ERROR_LOG(PIXELENGINE, "VIDEO plugin should set the token directly");
}
}
// SetFinish
// THIS IS EXECUTED FROM VIDEO THREAD
void SetFinish()
{
g_VideoInitialize.pScheduleEvent_Threadsafe(
0, et_SetFinishOnMainThread, 0);
INFO_LOG(PIXELENGINE, "VIDEO Set Finish");
}
} // end of namespace PixelEngine

View File

@ -0,0 +1,155 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELENGINE_H
#define _PIXELENGINE_H
#include "Common.h"
#include "pluginspecs_video.h"
#include "VideoCommon.h"
class PointerWrap;
namespace PixelEngine
{
// internal hardware addresses
enum
{
PE_ZCONF = 0x000, // Z Config
PE_ALPHACONF = 0x002, // Alpha Config
PE_DSTALPHACONF = 0x004, // Destination Alpha Config
PE_ALPHAMODE = 0x006, // Alpha Mode Config
PE_ALPHAREAD = 0x008, // Alpha Read
PE_CTRL_REGISTER = 0x00a, // Control
PE_TOKEN_REG = 0x00e, // Token
PE_BBOX_LEFT = 0x010, // Flip Left
PE_BBOX_RIGHT = 0x012, // Flip Right
PE_BBOX_TOP = 0x014, // Flip Top
PE_BBOX_BOTTOM = 0x016, // Flip Bottom
};
union UPEZConfReg
{
u16 Hex;
struct
{
u16 ZCompEnable : 1; // Z Comparator Enable
u16 Function : 3;
u16 ZUpdEnable : 1;
u16 : 11;
};
};
union UPEAlphaConfReg
{
u16 Hex;
struct
{
u16 BMMath : 1; // GX_BM_BLEND || GX_BM_SUBSTRACT
u16 BMLogic : 1; // GX_BM_LOGIC
u16 Dither : 1;
u16 ColorUpdEnable : 1;
u16 AlphaUpdEnable : 1;
u16 DstFactor : 3;
u16 SrcFactor : 3;
u16 Substract : 1; // Additive mode by default
u16 BlendOperator : 4;
};
};
union UPEDstAlphaConfReg
{
u16 Hex;
struct
{
u16 DstAlpha : 8;
u16 Enable : 1;
u16 : 7;
};
};
union UPEAlphaModeConfReg
{
u16 Hex;
struct
{
u16 Threshold : 8;
u16 CompareMode : 8;
};
};
union UPEAlphaReadReg
{
u16 Hex;
struct
{
u16 ReadMode : 3;
u16 : 13;
};
};
union UPECtrlReg
{
struct
{
u16 PETokenEnable : 1;
u16 PEFinishEnable : 1;
u16 PEToken : 1; // write only
u16 PEFinish : 1; // write only
u16 : 12;
};
u16 Hex;
UPECtrlReg() {Hex = 0; }
UPECtrlReg(u16 _hex) {Hex = _hex; }
};
struct PEReg
{
UPEZConfReg zconf;
UPEAlphaConfReg alphaConf;
UPEDstAlphaConfReg dstAlpha;
UPEAlphaModeConfReg alphaMode;
UPEAlphaReadReg alphaRead;
UPECtrlReg ctrl;
u16 unk0;
u16 token;
u16 boxLeft;
u16 boxRight;
u16 boxTop;
u16 boxBottom;
};
extern PEReg pereg;
void Init();
void DoState(PointerWrap &p);
// Read
void Read16(u16& _uReturnValue, const u32 _iAddress);
// Write
void Write16(const u16 _iValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
// gfx plugin support
void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
void SetFinish(void);
bool AllowIdleSkipping();
} // end of namespace PixelEngine
#endif

View File

@ -0,0 +1,321 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Rasterizer.h"
#include "HwRasterizer.h"
#include "EfbInterface.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Tev.h"
#include "Statistics.h"
#include "VideoConfig.h"
#define BLOCK_SIZE 8
namespace Rasterizer
{
s32 scissorLeft = 0;
s32 scissorTop = 0;
s32 scissorRight = 0;
s32 scissorBottom = 0;
Tev tev;
void Init()
{
tev.Init();
}
inline int iround(float x)
{
int t;
__asm
{
fld x
fistp t
}
return t;
}
void SetScissor()
{
int xoff = bpmem.scissorOffset.x * 2 - 342;
int yoff = bpmem.scissorOffset.y * 2 - 342;
scissorLeft = bpmem.scissorTL.x - xoff - 342;
if (scissorLeft < 0) scissorLeft = 0;
scissorTop = bpmem.scissorTL.y - yoff - 342;
if (scissorTop < 0) scissorTop = 0;
scissorRight = bpmem.scissorBR.x - xoff - 341;
if (scissorRight > EFB_WIDTH) scissorRight = EFB_WIDTH;
scissorBottom = bpmem.scissorBR.y - yoff - 341;
if (scissorBottom > EFB_HEIGHT) scissorBottom = EFB_HEIGHT;
}
void SetTevReg(int reg, int comp, bool konst, s16 color)
{
tev.SetRegColor(reg, comp, konst, color);
}
inline void Draw(s32 x, s32 y)
{
INCSTAT(stats.thisFrame.rasterizedPixels);
float zFloat = 1.0f + ZSlope.GetValue(x, y);
if(zFloat < 0|| zFloat > 1)
return;
u32 z = (u32)(zFloat * 0x00ffffff);
if (bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
{
// early z
if (!EfbInterface::ZCompare(x, y, z))
return;
}
float invW = 1.0f / WSlope.GetValue(x, y);
tev.Position[0] = x;
tev.Position[1] = y;
tev.Position[2] = z;
for(unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
{
for(int comp = 0; comp < 4; comp++)
tev.Color[i][comp] = (u8)ColorSlopes[i][comp].GetValue(x, y);
}
for(unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
if (xfregs.texMtxInfo[i].projection)
{
float q = TexSlopes[i][2].GetValue(x, y) * invW;
float invQ = invW / q;
tev.Uv[i][0] = TexSlopes[i][0].GetValue(x, y) * invQ * (bpmem.texcoords[i].s.scale_minus_1 + 1);
tev.Uv[i][1] = TexSlopes[i][1].GetValue(x, y) * invQ * (bpmem.texcoords[i].t.scale_minus_1 + 1);
tev.Lod[i] = 0;
}
else
{
tev.Uv[i][0] = TexSlopes[i][0].GetValue(x, y) * invW * (bpmem.texcoords[i].s.scale_minus_1 + 1);
tev.Uv[i][1] = TexSlopes[i][1].GetValue(x, y) * invW * (bpmem.texcoords[i].t.scale_minus_1 + 1);
tev.Lod[i] = 0;
}
}
tev.Draw();
}
void InitSlope(Slope *slope, float f1, float f2, float f3, float DX31, float DX12, float DY12, float DY31, float X1, float Y1)
{
float DF31 = f3 - f1;
float DF21 = f2 - f1;
float a = DF31 * -DY12 - DF21 * DY31;
float b = DX31 * DF21 + DX12 * DF31;
float c = -DX12 * DY31 - DX31 * -DY12;
slope->dfdx = -a / c;
slope->dfdy = -b / c;
slope->f0 = f1;
slope->x0 = X1;
slope->y0 = Y1;
}
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
{
INCSTAT(stats.thisFrame.numTrianglesDrawn);
if (g_Config.bHwRasterizer)
{
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
return;
}
// adapted from http://www.devmaster.net/forums/showthread.php?t=1884
// 28.4 fixed-pou32 coordinates. rounded to nearest
const s32 Y1 = iround(16.0f * v0->screenPosition[1]);
const s32 Y2 = iround(16.0f * v1->screenPosition[1]);
const s32 Y3 = iround(16.0f * v2->screenPosition[1]);
const s32 X1 = iround(16.0f * v0->screenPosition[0]);
const s32 X2 = iround(16.0f * v1->screenPosition[0]);
const s32 X3 = iround(16.0f * v2->screenPosition[0]);
// Deltas
const s32 DX12 = X1 - X2;
const s32 DX23 = X2 - X3;
const s32 DX31 = X3 - X1;
const s32 DY12 = Y1 - Y2;
const s32 DY23 = Y2 - Y3;
const s32 DY31 = Y3 - Y1;
// Fixed-pos32 deltas
const s32 FDX12 = DX12 << 4;
const s32 FDX23 = DX23 << 4;
const s32 FDX31 = DX31 << 4;
const s32 FDY12 = DY12 << 4;
const s32 FDY23 = DY23 << 4;
const s32 FDY31 = DY31 << 4;
// Bounding rectangle
s32 minx = (min(min(X1, X2), X3) + 0xF) >> 4;
s32 maxx = (max(max(X1, X2), X3) + 0xF) >> 4;
s32 miny = (min(min(Y1, Y2), Y3) + 0xF) >> 4;
s32 maxy = (max(max(Y1, Y2), Y3) + 0xF) >> 4;
// scissor
minx = max(minx, scissorLeft);
maxx = min(maxx, scissorRight);
miny = max(miny, scissorTop);
maxy = min(maxy, scissorBottom);
if (minx >= maxx || miny >= maxy)
return;
// Setup slopes
float fltx1 = v0->screenPosition[0];
float flty1 = v0->screenPosition[1];
float fltdx31 = v2->screenPosition[0] - fltx1;
float fltdx12 = fltx1 - v1->screenPosition[0];
float fltdy12 = flty1 - v1->screenPosition[1];
float fltdy31 = v2->screenPosition[1] - flty1;
float w[3] = { 1.0f / v0->projectedPosition[3], 1.0f / v1->projectedPosition[3], 1.0f / v2->projectedPosition[3] };
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
for(unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
{
for(int comp = 0; comp < 4; comp++)
InitSlope(&ColorSlopes[i][comp], v0->color[i][comp], v1->color[i][comp], v2->color[i][comp], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
}
for(unsigned int i = 0; i < bpmem.genMode.numtexgens; i++)
{
for(int comp = 0; comp < 3; comp++)
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31, fltx1, flty1);
}
// Start in corner of 8x8 block
minx &= ~(BLOCK_SIZE - 1);
miny &= ~(BLOCK_SIZE - 1);
// Half-edge constants
s32 C1 = DY12 * X1 - DX12 * Y1;
s32 C2 = DY23 * X2 - DX23 * Y2;
s32 C3 = DY31 * X3 - DX31 * Y3;
// Correct for fill convention
if(DY12 < 0 || (DY12 == 0 && DX12 > 0)) C1++;
if(DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
if(DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
// Loop through blocks
for(s32 y = miny; y < maxy; y += BLOCK_SIZE)
{
for(s32 x = minx; x < maxx; x += BLOCK_SIZE)
{
// Corners of block
s32 x0 = x << 4;
s32 x1 = (x + BLOCK_SIZE - 1) << 4;
s32 y0 = y << 4;
s32 y1 = (y + BLOCK_SIZE - 1) << 4;
// Evaluate half-space functions
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
// Skip block when outside an edge
if(a == 0x0 || b == 0x0 || c == 0x0) continue;
// Accept whole block when totally covered
if(a == 0xF && b == 0xF && c == 0xF)
{
for(s32 iy = 0; iy < BLOCK_SIZE; iy++)
{
for(s32 ix = x; ix < x + BLOCK_SIZE; ix++)
{
Draw(ix, iy + y);
}
}
}
else // Partially covered block
{
s32 CY1 = C1 + DX12 * y0 - DY12 * x0;
s32 CY2 = C2 + DX23 * y0 - DY23 * x0;
s32 CY3 = C3 + DX31 * y0 - DY31 * x0;
for(s32 iy = y; iy < y + BLOCK_SIZE; iy++)
{
s32 CX1 = CY1;
s32 CX2 = CY2;
s32 CX3 = CY3;
for(s32 ix = x; ix < x + BLOCK_SIZE; ix++)
{
if(CX1 > 0 && CX2 > 0 && CX3 > 0)
{
Draw(ix, iy);
}
CX1 -= FDY12;
CX2 -= FDY23;
CX3 -= FDY31;
}
CY1 += FDX12;
CY2 += FDX23;
CY3 += FDX31;
}
}
}
}
}
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RASTERIZER_H_
#define _RASTERIZER_H_
#include "NativeVertexFormat.h"
namespace Rasterizer
{
void Init();
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2);
void SetScissor();
void SetTevReg(int reg, int comp, bool konst, s16 color);
struct Slope
{
float dfdx;
float dfdy;
float f0;
float x0;
float y0;
float GetValue(s32 x, s32 y) { return f0 + (dfdx * (x - x0)) + (dfdy * (y - y0)); }
};
static Slope ZSlope;
static Slope WSlope;
static Slope ColorSlopes[2][4];
static Slope TexSlopes[8][3];
}
#endif

View File

@ -0,0 +1,201 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "GLUtil.h"
#include "Renderer.h"
#include "main.h"
#include "Statistics.h"
#include "../../Plugin_VideoOGL/Src/rasterfont.h"
#define VSYNC_ENABLED 0
static GLuint s_RenderTarget = 0;
RasterFont* s_pfont = NULL;
void Renderer::Init(SVideoInitialize *_pVideoInitialize)
{
if (!OpenGL_Create(g_VideoInitialize, 640, 480)) // 640x480 will be the default if all else fails
{
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
return;
}
_pVideoInitialize->pPeekMessages = g_VideoInitialize.pPeekMessages;
_pVideoInitialize->pUpdateFPSDisplay = g_VideoInitialize.pUpdateFPSDisplay;
_pVideoInitialize->pWindowHandle = g_VideoInitialize.pWindowHandle;
}
void Renderer::Shutdown()
{
glDeleteTextures(1, &s_RenderTarget);
delete s_pfont;
s_pfont = 0;
}
void Renderer::Prepare()
{
OpenGL_MakeCurrent();
// Init extension support.
if (glewInit() != GLEW_OK) {
ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?");
return;
}
// Handle VSync on/off
#ifdef _WIN32
if (WGLEW_EXT_swap_control)
wglSwapIntervalEXT(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)Does your video card support OpenGL 2.x?");
#elif defined(HAVE_X11) && HAVE_X11
if (glXSwapIntervalSGI)
glXSwapIntervalSGI(VSYNC_ENABLED);
else
ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)");
#endif
glStencilFunc(GL_ALWAYS, 0, 0);
// used by hw rasterizer if it enables blending and depth test
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_SCISSOR_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
//glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
s_pfont = new RasterFont();
// legacy multitexturing: select texture channel only.
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glGenTextures(1, &s_RenderTarget);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
void Renderer::RenderText(const char* pstr, int left, int top, u32 color)
{
int nBackbufferWidth = (int)OpenGL_GetBackbufferWidth();
int nBackbufferHeight = (int)OpenGL_GetBackbufferHeight();
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
s_pfont->printMultilineText(pstr,
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
}
void Renderer::DrawDebugText()
{
char debugtext_buffer[8192];
char *p = debugtext_buffer;
p[0] = 0;
if (g_Config.bShowStats)
{
p+=sprintf(p,"Objects: %i\n",stats.thisFrame.numDrawnObjects);
p+=sprintf(p,"Primatives: %i\n",stats.thisFrame.numPrimatives);
p+=sprintf(p,"Vertices Loaded: %i\n",stats.thisFrame.numVerticesLoaded);
p+=sprintf(p,"Triangles Input: %i\n",stats.thisFrame.numTrianglesIn);
p+=sprintf(p,"Triangles Rejected: %i\n",stats.thisFrame.numTrianglesRejected);
p+=sprintf(p,"Triangles Culled: %i\n",stats.thisFrame.numTrianglesCulled);
p+=sprintf(p,"Triangles Clipped: %i\n",stats.thisFrame.numTrianglesClipped);
p+=sprintf(p,"Triangles Drawn: %i\n",stats.thisFrame.numTrianglesDrawn);
p+=sprintf(p,"Rasterized Pix: %i\n",stats.thisFrame.rasterizedPixels);
p+=sprintf(p,"TEV Pix In: %i\n",stats.thisFrame.tevPixelsIn);
p+=sprintf(p,"TEV Pix Out: %i\n",stats.thisFrame.tevPixelsOut);
}
// Render a shadow, and then the text.
Renderer::RenderText(debugtext_buffer, 21, 21, 0xDD000000);
Renderer::RenderText(debugtext_buffer, 20, 20, 0xFFFFFF00);
}
void Renderer::DrawTexture(u8 *texture, int width, int height)
{
OpenGL_Update(); // just updates the render window position and the backbuffer size
GLsizei glWidth = (GLsizei)OpenGL_GetBackbufferWidth();
GLsizei glHeight = (GLsizei)OpenGL_GetBackbufferHeight();
// Update GLViewPort
glViewport(0, 0, glWidth, glHeight);
glScissor(0, 0, glWidth, glHeight);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GL_REPORT_ERRORD();
GLfloat u_max = (GLfloat)width;
GLfloat v_max = (GLfloat)glHeight;
glBegin(GL_QUADS);
glTexCoord2f(0, v_max); glVertex2f(-1, -1);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glTexCoord2f(u_max, 0); glVertex2f( 1, 1);
glTexCoord2f(u_max, v_max); glVertex2f( 1, -1);
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void Renderer::SwapBuffer()
{
DrawDebugText();
glFlush();
OpenGL_SwapBuffers();
GL_REPORT_ERRORD();
stats.ResetFrame();
// Clear framebuffer
glClearColor(0, 0, 0, 0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GL_REPORT_ERRORD();
}

View File

@ -0,0 +1,37 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _RENDERER_H_
#define _RENDERER_H_
#include "PluginSpecs_Video.h"
namespace Renderer
{
void Init(SVideoInitialize *_pVideoInitialize);
void Prepare();
void Shutdown();
void RenderText(const char* pstr, int left, int top, u32 color);
void DrawDebugText();
void DrawTexture(u8 *texture, int width, int height);
void SwapBuffer();
}
#endif

View File

@ -0,0 +1,143 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "SetupUnit.h"
#include "CPMemLoader.h"
#include "OpcodeDecoder.h"
#include "Statistics.h"
#include "Clipper.h"
void SetupUnit::Init(u8 primitiveType)
{
m_PrimType = primitiveType;
m_VertexCounter = 0;
m_VertPointer[0] = &m_Vertices[0];
m_VertPointer[1] = &m_Vertices[1];
m_VertPointer[2] = &m_Vertices[2];
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupVertex()
{
switch(m_PrimType)
{
case GX_DRAW_QUADS:
SetupQuad();
break;
case GX_DRAW_TRIANGLES:
SetupTriangle();
break;
case GX_DRAW_TRIANGLE_STRIP:
SetupTriStrip();
break;
case GX_DRAW_TRIANGLE_FAN:
SetupTriFan();
break;
case GX_DRAW_LINES:
SetupLine();
break;
case GX_DRAW_LINE_STRIP:
SetupLineStrip();
break;
case GX_DRAW_POINTS:
SetupPoint();
break;
}
}
void SetupUnit::SetupQuad()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter++;
m_VertexCounter &= 3;
m_VertWritePointer = &m_Vertices[m_VertexCounter & 1];
OutputVertexData* temp = m_VertPointer[1];
m_VertPointer[1] = m_VertPointer[2];
m_VertPointer[2] = temp;
}
void SetupUnit::SetupTriangle()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter = 0;
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupTriStrip()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter++;
m_VertPointer[2 - (m_VertexCounter & 1)] = m_VertPointer[0];
m_VertWritePointer = m_VertPointer[0];
m_VertPointer[0] = &m_Vertices[(m_VertexCounter + 1) % 3];
}
void SetupUnit::SetupTriFan()
{
if (m_VertexCounter < 2)
{
m_VertexCounter++;
m_VertWritePointer = m_VertPointer[m_VertexCounter];
return;
}
Clipper::ProcessTriangle(m_VertPointer[0], m_VertPointer[1], m_VertPointer[2]);
m_VertexCounter++;
m_VertPointer[1] = m_VertPointer[2];
m_VertPointer[2] = &m_Vertices[2 - (m_VertexCounter & 1)];
m_VertWritePointer = m_VertPointer[2];
}
void SetupUnit::SetupLine()
{}
void SetupUnit::SetupLineStrip()
{}
void SetupUnit::SetupPoint()
{}

View File

@ -0,0 +1,50 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _SETUPUNIT_H_
#define _SETUPUNIT_H_
#include "Common.h"
#include "NativeVertexFormat.h"
class SetupUnit
{
u8 m_PrimType;
int m_VertexCounter;
OutputVertexData m_Vertices[3];
OutputVertexData *m_VertPointer[3];
OutputVertexData *m_VertWritePointer;
void SetupQuad();
void SetupTriangle();
void SetupTriStrip();
void SetupTriFan();
void SetupLine();
void SetupLineStrip();
void SetupPoint();
public:
void Init(u8 primitiveType);
OutputVertexData* GetVertex() { return m_VertWritePointer; }
void SetupVertex();
};
#endif

View File

@ -0,0 +1,38 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Statistics.h"
Statistics stats;
template <class T>
void Xchg(T& a, T&b)
{
T c = a;
a = b;
b = c;
}
Statistics::Statistics()
{
frameCount = 0;
}
void Statistics::ResetFrame()
{
memset(&thisFrame, 0, sizeof(ThisFrame));
}

View File

@ -0,0 +1,63 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "CommonTypes.h"
#include "VideoConfig.h"
#ifndef _STATISTICS_H
#define _STATISTICS_H
struct Statistics
{
struct ThisFrame
{
u32 numDrawnObjects;
u32 numPrimatives;
u32 numVerticesLoaded;
u32 numVerticesOut;
u32 numTrianglesIn;
u32 numTrianglesRejected;
u32 numTrianglesCulled;
u32 numTrianglesClipped;
u32 numTrianglesDrawn;
u32 rasterizedPixels;
u32 tevPixelsIn;
u32 tevPixelsOut;
};
u32 frameCount;
Statistics();
ThisFrame thisFrame;
void ResetFrame();
};
extern Statistics stats;
#if (STATISTICS)
#define INCSTAT(a) (a)++;
#define ADDSTAT(a,b) (a)+=(b);
#define SETSTAT(a,x) (a)=(int)(x);
#else
#define INCSTAT(a) ;
#define ADDSTAT(a,b) ;
#define SETSTAT(a,x) ;
#endif
#endif // _STATISTICS_H

View File

@ -0,0 +1,722 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Tev.h"
#include "EfbInterface.h"
#include "TextureSampler.h"
#include "Statistics.h"
#include <math.h>
void Tev::Init()
{
FixedConstants[0] = 0;
FixedConstants[1] = 31;
FixedConstants[2] = 63;
FixedConstants[3] = 95;
FixedConstants[4] = 127;
FixedConstants[5] = 159;
FixedConstants[6] = 191;
FixedConstants[7] = 223;
FixedConstants[8] = 255;
for (int i = 0; i < 4; i++)
Zero16[i] = 0;
m_ColorInputLUT[0][0] = &Reg[0][RED_C]; m_ColorInputLUT[0][1] = &Reg[0][GRN_C]; m_ColorInputLUT[0][2] = &Reg[0][BLU_C]; // prev.rgb
m_ColorInputLUT[1][0] = &Reg[0][ALP_C]; m_ColorInputLUT[1][1] = &Reg[0][ALP_C]; m_ColorInputLUT[1][2] = &Reg[0][ALP_C]; // prev.aaa
m_ColorInputLUT[2][0] = &Reg[1][RED_C]; m_ColorInputLUT[2][1] = &Reg[1][GRN_C]; m_ColorInputLUT[2][2] = &Reg[1][BLU_C]; // c0.rgb
m_ColorInputLUT[3][0] = &Reg[1][ALP_C]; m_ColorInputLUT[3][1] = &Reg[1][ALP_C]; m_ColorInputLUT[3][2] = &Reg[1][ALP_C]; // c0.aaa
m_ColorInputLUT[4][0] = &Reg[2][RED_C]; m_ColorInputLUT[4][1] = &Reg[2][GRN_C]; m_ColorInputLUT[4][2] = &Reg[2][BLU_C]; // c1.rgb
m_ColorInputLUT[5][0] = &Reg[2][ALP_C]; m_ColorInputLUT[5][1] = &Reg[2][ALP_C]; m_ColorInputLUT[5][2] = &Reg[2][ALP_C]; // c1.aaa
m_ColorInputLUT[6][0] = &Reg[3][RED_C]; m_ColorInputLUT[6][1] = &Reg[3][GRN_C]; m_ColorInputLUT[6][2] = &Reg[3][BLU_C]; // c2.rgb
m_ColorInputLUT[7][0] = &Reg[3][ALP_C]; m_ColorInputLUT[7][1] = &Reg[3][ALP_C]; m_ColorInputLUT[7][2] = &Reg[3][ALP_C]; // c2.aaa
m_ColorInputLUT[8][0] = &TexColor[RED_C]; m_ColorInputLUT[8][1] = &TexColor[GRN_C]; m_ColorInputLUT[8][2] = &TexColor[BLU_C]; // tex.rgb
m_ColorInputLUT[9][0] = &TexColor[ALP_C]; m_ColorInputLUT[9][1] = &TexColor[ALP_C]; m_ColorInputLUT[9][2] = &TexColor[ALP_C]; // tex.aaa
m_ColorInputLUT[10][0] = &RasColor[RED_C]; m_ColorInputLUT[10][1] = &RasColor[GRN_C]; m_ColorInputLUT[10][2] = &RasColor[BLU_C]; // ras.rgb
m_ColorInputLUT[11][0] = &RasColor[ALP_C]; m_ColorInputLUT[11][1] = &RasColor[ALP_C]; m_ColorInputLUT[11][2] = &RasColor[ALP_C]; // ras.rgb
m_ColorInputLUT[12][0] = &FixedConstants[8]; m_ColorInputLUT[12][1] = &FixedConstants[8]; m_ColorInputLUT[12][2] = &FixedConstants[8]; // one
m_ColorInputLUT[13][0] = &FixedConstants[4]; m_ColorInputLUT[13][1] = &FixedConstants[4]; m_ColorInputLUT[13][2] = &FixedConstants[4]; // half
m_ColorInputLUT[14][0] = &StageKonst[0]; m_ColorInputLUT[14][1] = &StageKonst[1]; m_ColorInputLUT[14][2] = &StageKonst[2]; // konst
m_ColorInputLUT[15][0] = &FixedConstants[0]; m_ColorInputLUT[15][1] = &FixedConstants[0]; m_ColorInputLUT[15][2] = &FixedConstants[0]; // zero
m_AlphaInputLUT[0] = &Reg[0][ALP_C]; // prev.a
m_AlphaInputLUT[1] = &Reg[1][ALP_C]; // c0.a
m_AlphaInputLUT[2] = &Reg[2][ALP_C]; // c1.a
m_AlphaInputLUT[3] = &Reg[3][ALP_C]; // c2.a
m_AlphaInputLUT[4] = &TexColor[ALP_C]; // tex.a
m_AlphaInputLUT[5] = &RasColor[ALP_C]; // ras.a
m_AlphaInputLUT[6] = &StageKonst[ALP_C]; // konst.a
m_AlphaInputLUT[7] = &Zero16[ALP_C]; // zero
for (int comp = 0; comp < 4; comp++)
{
m_KonstLUT[0][comp] = &FixedConstants[8];
m_KonstLUT[1][comp] = &FixedConstants[7];
m_KonstLUT[2][comp] = &FixedConstants[6];
m_KonstLUT[3][comp] = &FixedConstants[5];
m_KonstLUT[4][comp] = &FixedConstants[4];
m_KonstLUT[5][comp] = &FixedConstants[3];
m_KonstLUT[6][comp] = &FixedConstants[2];
m_KonstLUT[7][comp] = &FixedConstants[1];
m_KonstLUT[12][comp] = &KonstantColors[0][comp];
m_KonstLUT[13][comp] = &KonstantColors[1][comp];
m_KonstLUT[14][comp] = &KonstantColors[2][comp];
m_KonstLUT[15][comp] = &KonstantColors[3][comp];
m_KonstLUT[16][comp] = &KonstantColors[0][RED_C];
m_KonstLUT[17][comp] = &KonstantColors[1][RED_C];
m_KonstLUT[18][comp] = &KonstantColors[2][RED_C];
m_KonstLUT[19][comp] = &KonstantColors[3][RED_C];
m_KonstLUT[20][comp] = &KonstantColors[0][GRN_C];
m_KonstLUT[21][comp] = &KonstantColors[1][GRN_C];
m_KonstLUT[22][comp] = &KonstantColors[2][GRN_C];
m_KonstLUT[23][comp] = &KonstantColors[3][GRN_C];
m_KonstLUT[24][comp] = &KonstantColors[0][BLU_C];
m_KonstLUT[25][comp] = &KonstantColors[1][BLU_C];
m_KonstLUT[26][comp] = &KonstantColors[2][BLU_C];
m_KonstLUT[27][comp] = &KonstantColors[3][BLU_C];
m_KonstLUT[28][comp] = &KonstantColors[0][ALP_C];
m_KonstLUT[29][comp] = &KonstantColors[1][ALP_C];
m_KonstLUT[30][comp] = &KonstantColors[2][ALP_C];
m_KonstLUT[31][comp] = &KonstantColors[3][ALP_C];
}
m_BiasLUT[0] = 0;
m_BiasLUT[1] = 128;
m_BiasLUT[2] = -128;
m_BiasLUT[3] = 0;
m_ScaleLShiftLUT[0] = 0;
m_ScaleLShiftLUT[1] = 1;
m_ScaleLShiftLUT[2] = 2;
m_ScaleLShiftLUT[3] = 0;
m_ScaleRShiftLUT[0] = 0;
m_ScaleRShiftLUT[1] = 0;
m_ScaleRShiftLUT[2] = 0;
m_ScaleRShiftLUT[3] = 1;
}
inline s16 Clamp255(s16 in)
{
return in>255?255:(in<0?0:in);
}
inline void Tev::SetRasColor(int colorChan, int swaptable)
{
switch(colorChan)
{
case 0: // Color0
{
u8 *color = Color[0];
RasColor[0] = color[bpmem.tevksel[swaptable].swap1];
RasColor[1] = color[bpmem.tevksel[swaptable].swap2];
swaptable++;
RasColor[2] = color[bpmem.tevksel[swaptable].swap1];
RasColor[3] = color[bpmem.tevksel[swaptable].swap2];
}
break;
case 1: // Color1
{
u8 *color = Color[1];
RasColor[0] = color[bpmem.tevksel[swaptable].swap1];
RasColor[1] = color[bpmem.tevksel[swaptable].swap2];
swaptable++;
RasColor[2] = color[bpmem.tevksel[swaptable].swap1];
RasColor[3] = color[bpmem.tevksel[swaptable].swap2];
}
break;
case 5: // alpha bump
{
for(int i = 0; i < 4; i++)
RasColor[i] = AlphaBump;
}
break;
case 6: // alpha bump normalized
{
u8 normalized = AlphaBump | AlphaBump >> 5;
for(int i = 0; i < 4; i++)
RasColor[i] = normalized;
}
break;
default: // zero
{
for(int i = 0; i < 4; i++)
RasColor[i] = 0;
}
break;
}
}
void Tev::DrawColorRegular(TevStageCombiner::ColorCombiner &cc)
{
struct {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
} InputReg;
for (int i = 0; i < 3; i++)
{
InputReg.a = *m_ColorInputLUT[cc.a][i];
InputReg.b = *m_ColorInputLUT[cc.b][i];
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
u16 c = InputReg.c + (InputReg.c >> 7);
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
temp = cc.op?(-temp >> 8):(temp >> 8);
s32 result = InputReg.d + temp + m_BiasLUT[cc.bias];
result = result << m_ScaleLShiftLUT[cc.shift];
result = result >> m_ScaleRShiftLUT[cc.shift];
Reg[cc.dest][RED_C + i] = result;
}
}
void Tev::DrawColorCompare(TevStageCombiner::ColorCombiner &cc)
{
int cmp = (cc.shift<<1)|cc.op|8; // comparemode stored here
u32 a;
u32 b;
struct {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
} InputReg;
switch(cmp) {
case TEVCMP_R8_GT:
{
a = *m_ColorInputLUT[cc.a][RED_C] & 0xff;
b = *m_ColorInputLUT[cc.b][RED_C] & 0xff;
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_R8_EQ:
{
a = *m_ColorInputLUT[cc.a][RED_C] & 0xff;
b = *m_ColorInputLUT[cc.b][RED_C] & 0xff;
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_GR16_GT:
{
a = ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
b = ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_GR16_EQ:
{
a = ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
b = ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_BGR24_GT:
{
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_BGR24_EQ:
{
a = ((*m_ColorInputLUT[cc.a][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.a][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.a][RED_C] & 0xff);
b = ((*m_ColorInputLUT[cc.b][BLU_C] & 0xff) << 16) | ((*m_ColorInputLUT[cc.b][GRN_C] & 0xff) << 8) | (*m_ColorInputLUT[cc.b][RED_C] & 0xff);
for (int i = 0; i < 3; i++)
{
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
}
break;
case TEVCMP_RGB8_GT:
for (int i = 0; i < 3; i++)
{
InputReg.a = *m_ColorInputLUT[cc.a][i];
InputReg.b = *m_ColorInputLUT[cc.b][i];
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
}
break;
case TEVCMP_RGB8_EQ:
for (int i = 0; i < 3; i++)
{
InputReg.a = *m_ColorInputLUT[cc.a][i];
InputReg.b = *m_ColorInputLUT[cc.b][i];
InputReg.c = *m_ColorInputLUT[cc.c][i];
InputReg.d = *m_ColorInputLUT[cc.d][i];
Reg[cc.dest][RED_C + i] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
}
break;
}
}
void Tev::DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac)
{
struct {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
} InputReg;
InputReg.a = *m_AlphaInputLUT[ac.a];
InputReg.b = *m_AlphaInputLUT[ac.b];
InputReg.c = *m_AlphaInputLUT[ac.c];
InputReg.d = *m_AlphaInputLUT[ac.d];
u16 c = InputReg.c + (InputReg.c >> 7);
s32 temp = InputReg.a * (256 - c) + (InputReg.b * c);
temp = ac.op?(-temp >> 8):(temp >> 8);
s32 result = InputReg.d + temp + m_BiasLUT[ac.bias];
result = result << m_ScaleLShiftLUT[ac.shift];
result = result >> m_ScaleRShiftLUT[ac.shift];
Reg[ac.dest][ALP_C] = result;
}
void Tev::DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac)
{
int cmp = (ac.shift<<1)|ac.op|8; // comparemode stored here
u32 a;
u32 b;
struct {
unsigned a : 8;
unsigned b : 8;
unsigned c : 8;
signed d : 11;
} InputReg;
switch(cmp) {
case TEVCMP_R8_GT:
{
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
break;
case TEVCMP_R8_EQ:
{
a = m_AlphaInputLUT[ac.a][RED_C] & 0xff;
b = m_AlphaInputLUT[ac.b][RED_C] & 0xff;
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
break;
case TEVCMP_GR16_GT:
{
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
break;
case TEVCMP_GR16_EQ:
{
a = ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
b = ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
break;
case TEVCMP_BGR24_GT:
{
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a > b) ? InputReg.c : 0);
}
break;
case TEVCMP_BGR24_EQ:
{
a = ((m_AlphaInputLUT[ac.a][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.a][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.a][RED_C] & 0xff);
b = ((m_AlphaInputLUT[ac.b][BLU_C] & 0xff) << 16) | ((m_AlphaInputLUT[ac.b][GRN_C] & 0xff) << 8) | (m_AlphaInputLUT[ac.b][RED_C] & 0xff);
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((a == b) ? InputReg.c : 0);
}
break;
case TEVCMP_A8_GT:
{
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a > InputReg.b) ? InputReg.c : 0);
}
break;
case TEVCMP_A8_EQ:
{
InputReg.a = m_AlphaInputLUT[ac.a][ALP_C];
InputReg.b = m_AlphaInputLUT[ac.b][ALP_C];
InputReg.c = m_AlphaInputLUT[ac.c][ALP_C];
InputReg.d = m_AlphaInputLUT[ac.d][ALP_C];
Reg[ac.dest][ALP_C] = InputReg.d + ((InputReg.a == InputReg.b) ? InputReg.c : 0);
}
break;
}
}
static bool AlphaCompare(int alpha, int ref, int comp)
{
switch(comp) {
case ALPHACMP_ALWAYS: return true;
case ALPHACMP_NEVER: return false;
case ALPHACMP_LEQUAL: return alpha <= ref;
case ALPHACMP_LESS: return alpha < ref;
case ALPHACMP_GEQUAL: return alpha >= ref;
case ALPHACMP_GREATER: return alpha > ref;
case ALPHACMP_EQUAL: return alpha == ref;
case ALPHACMP_NEQUAL: return alpha != ref;
}
return true;
}
static bool AlphaTest(int alpha)
{
bool comp0 = AlphaCompare(alpha, bpmem.alphaFunc.ref0, bpmem.alphaFunc.comp0);
bool comp1 = AlphaCompare(alpha, bpmem.alphaFunc.ref1, bpmem.alphaFunc.comp1);
switch (bpmem.alphaFunc.logic) {
case 0: return comp0 && comp1; // and
case 1: return comp0 || comp1; // or
case 2: return comp0 ^ comp1; // xor
case 3: return !(comp0 ^ comp1); // xnor
}
return true;
}
inline float WrapIndirectCoord(float coord, int wrapMode)
{
switch (wrapMode) {
case ITW_OFF:
return coord;
case ITW_256:
return fmod(coord, 256);
case ITW_128:
return fmod(coord, 128);
case ITW_64:
return fmod(coord, 64);
case ITW_32:
return fmod(coord, 32);
case ITW_16:
return fmod(coord, 16);
case ITW_0:
return 0;
}
return 0;
}
void Tev::Indirect(unsigned int stageNum, float s, float t)
{
TevStageIndirect &indirect = bpmem.tevind[stageNum];
u8 *indmap = IndirectTex[indirect.bt];
float indcoord[3];
// alpha bump select
switch (indirect.bs) {
case ITBA_OFF:
AlphaBump = 0;
break;
case ITBA_S:
AlphaBump = indmap[ALP_C];
break;
case ITBA_T:
AlphaBump = indmap[BLU_C];
break;
case ITBA_U:
AlphaBump = indmap[GRN_C];
break;
}
// bias select
s16 biasValue = indirect.fmt==ITF_8?-128:1;
s16 bias[3];
bias[0] = indirect.bias&1?biasValue:0;
bias[1] = indirect.bias&2?biasValue:0;
bias[2] = indirect.bias&4?biasValue:0;
// format
switch(indirect.fmt) {
case ITF_8:
indcoord[0] = (float)indmap[ALP_C] + bias[0];
indcoord[1] = (float)indmap[BLU_C] + bias[1];
indcoord[2] = (float)indmap[GRN_C] + bias[2];
AlphaBump = AlphaBump & 0xf8;
break;
case ITF_5:
indcoord[0] = (float)(indmap[ALP_C] & 0x1f) + bias[0];
indcoord[1] = (float)(indmap[BLU_C] & 0x1f) + bias[1];
indcoord[2] = (float)(indmap[GRN_C] & 0x1f) + bias[2];
AlphaBump = AlphaBump & 0xe0;
break;
case ITF_4:
indcoord[0] = (float)(indmap[ALP_C] & 0x0f) + bias[0];
indcoord[1] = (float)(indmap[BLU_C] & 0x0f) + bias[1];
indcoord[2] = (float)(indmap[GRN_C] & 0x0f) + bias[2];
AlphaBump = AlphaBump & 0xf0;
break;
case ITF_3:
indcoord[0] = (float)(indmap[ALP_C] & 0x07) + bias[0];
indcoord[1] = (float)(indmap[BLU_C] & 0x07) + bias[1];
indcoord[2] = (float)(indmap[GRN_C] & 0x07) + bias[2];
AlphaBump = AlphaBump & 0xf8;
break;
}
float indtevtrans[2] = { 0,0 };
// matrix multiply
int indmtxid = indirect.mid & 3;
if (indmtxid)
{
IND_MTX &indmtx = bpmem.indmtx[indmtxid - 1];
int scale = ((u32)indmtx.col0.s0 << 0) |
((u32)indmtx.col1.s1 << 2) |
((u32)indmtx.col2.s2 << 4);
float fscale = 0.0f;
switch (indirect.mid & 12) {
case 0:
fscale = powf(2.0f, (float)(scale - 17)) / 1024.0f;
indtevtrans[0] = indmtx.col0.ma * indcoord[0] + indmtx.col1.mc * indcoord[1] + indmtx.col2.me * indcoord[2];
indtevtrans[1] = indmtx.col0.mb * indcoord[0] + indmtx.col1.md * indcoord[1] + indmtx.col2.mf * indcoord[2];
break;
case 4: // s matrix
fscale = powf(2.0f, (float)(scale - 17)) / 256;
indtevtrans[0] = s * indcoord[0];
indtevtrans[1] = t * indcoord[0];
break;
case 8: // t matrix
fscale = powf(2.0f, (float)(scale - 17)) / 256;
indtevtrans[0] = s * indcoord[1];
indtevtrans[1] = t * indcoord[1];
break;
}
indtevtrans[0] *= fscale;
indtevtrans[1] *= fscale;
}
if (indirect.fb_addprev)
{
TexCoord[0] += WrapIndirectCoord(s, indirect.sw) + indtevtrans[0];
TexCoord[1] += WrapIndirectCoord(t, indirect.tw) + indtevtrans[1];
}
else
{
TexCoord[0] = WrapIndirectCoord(s, indirect.sw) + indtevtrans[0];
TexCoord[1] = WrapIndirectCoord(t, indirect.tw) + indtevtrans[1];
}
}
void Tev::Draw()
{
_assert_(Position[0] >= 0 && Position[0] < EFB_WIDTH);
_assert_(Position[1] >= 0 && Position[1] < EFB_HEIGHT);
INCSTAT(stats.thisFrame.tevPixelsIn);
for (unsigned int stageNum = 0; stageNum < bpmem.genMode.numindstages; stageNum++)
{
int stageNum2 = stageNum >> 1;
int stageOdd = stageNum&1;
u32 texcoordSel = bpmem.tevindref.getTexCoord(stageNum);
u32 texmap = bpmem.tevindref.getTexMap(stageNum);
float scaleS = bpmem.texscale[stageNum2].getScaleS(stageOdd);
float scaleT = bpmem.texscale[stageNum2].getScaleT(stageOdd);
TextureSampler::Sample(Uv[texcoordSel][0] * scaleS, Uv[texcoordSel][1] * scaleT, Lod[texcoordSel], texmap, IndirectTex[stageNum]);
}
for (unsigned int stageNum = 0; stageNum <= bpmem.genMode.numtevstages; stageNum++)
{
int stageNum2 = stageNum >> 1;
int stageOdd = stageNum&1;
TwoTevStageOrders &order = bpmem.tevorders[stageNum2];
TevKSel &kSel = bpmem.tevksel[stageNum2];
// stage combiners
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[stageNum].colorC;
TevStageCombiner::AlphaCombiner &ac = bpmem.combiners[stageNum].alphaC;
int texcoordSel = order.getTexCoord(stageOdd);
int texmap = order.getTexMap(stageOdd);
Indirect(stageNum, Uv[texcoordSel][0], Uv[texcoordSel][1]);
// sample texture
if (order.getEnable(stageOdd))
{
u8 texel[4];
TextureSampler::Sample(TexCoord[0], TexCoord[1], Lod[texcoordSel], texmap, texel);
int swaptable = ac.tswap * 2;
TexColor[0] = texel[bpmem.tevksel[swaptable].swap1];
TexColor[1] = texel[bpmem.tevksel[swaptable].swap2];
swaptable++;
TexColor[2] = texel[bpmem.tevksel[swaptable].swap1];
TexColor[3] = texel[bpmem.tevksel[swaptable].swap2];
}
// set konst for this stage
int kc = kSel.getKC(stageOdd);
int ka = kSel.getKA(stageOdd);
StageKonst[RED_C] = *(m_KonstLUT[kc][RED_C]);
StageKonst[GRN_C] = *(m_KonstLUT[kc][GRN_C]);
StageKonst[BLU_C] = *(m_KonstLUT[kc][BLU_C]);
StageKonst[ALP_C] = *(m_KonstLUT[ka][ALP_C]);
// set color
SetRasColor(order.getColorChan(stageOdd), ac.rswap * 2);
// combine inputs
if (cc.bias != 3)
DrawColorRegular(cc);
else
DrawColorCompare(cc);
if (cc.clamp)
{
Reg[cc.dest][RED_C] = Clamp255(Reg[cc.dest][RED_C]);
Reg[cc.dest][GRN_C] = Clamp255(Reg[cc.dest][GRN_C]);
Reg[cc.dest][BLU_C] = Clamp255(Reg[cc.dest][BLU_C]);
}
if (ac.bias != 3)
DrawAlphaRegular(ac);
else
DrawAlphaCompare(ac);
if (ac.clamp)
Reg[ac.dest][ALP_C] = Clamp255(Reg[ac.dest][ALP_C]);
}
// convert to 8 bits per component
u8 output[4] = {(u8)Reg[0][0], (u8)Reg[0][1], (u8)Reg[0][2], (u8)Reg[0][3]};
if (!AlphaTest(output[ALP_C]))
return;
// z texture
if (bpmem.ztex2.op)
{
s32 ztex = bpmem.ztex1.bias;
switch (bpmem.ztex2.type) {
case 0: // 8 bit
ztex += TexColor[RED_C];
break;
case 1: // 16 bit
ztex += TexColor[ALP_C] << 8 | TexColor[RED_C];
break;
case 2: // 24 bit
ztex += TexColor[RED_C] << 16 | TexColor[GRN_C] << 8 | TexColor[BLU_C];
break;
}
switch (bpmem.ztex2.op) {
case ZTEXTURE_ADD:
Position[2] += ztex;
break;
case ZTEXTURE_REPLACE:
Position[2] = ztex;
break;
}
}
if (!bpmem.zcontrol.zcomploc && bpmem.zmode.testenable)
{
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
return;
}
INCSTAT(stats.thisFrame.tevPixelsOut);
EfbInterface::BlendTev(Position[0], Position[1], output);
}
void Tev::SetRegColor(int reg, int comp, bool konst, s16 color)
{
if (konst)
{
KonstantColors[reg][comp] = color;
}
else
{
Reg[reg][comp] = color;
}
}

View File

@ -0,0 +1,69 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TEV_H_
#define _TEV_H_
#include "BPMemLoader.h"
class Tev
{
// color order: RGBA
s16 Reg[4][4];
s16 KonstantColors[4][4];
s16 FixedConstants[9];
s16 TexColor[4];
s16 RasColor[4];
s16 StageKonst[4];
s16 Zero16[4];
u8 AlphaBump;
u8 IndirectTex[4][4];
float TexCoord[2];
s16 *m_ColorInputLUT[16][3];
s16 *m_AlphaInputLUT[8]; // values must point to RGBA color
s16 *m_KonstLUT[32][4];
u8 *m_RasColorLUT[8];
s16 m_BiasLUT[4];
u8 m_ScaleLShiftLUT[4];
u8 m_ScaleRShiftLUT[4];
void SetRasColor(int colorChan, int swaptable);
void DrawColorRegular(TevStageCombiner::ColorCombiner &cc);
void DrawColorCompare(TevStageCombiner::ColorCombiner &cc);
void DrawAlphaRegular(TevStageCombiner::AlphaCombiner &ac);
void DrawAlphaCompare(TevStageCombiner::AlphaCombiner &ac);
void Indirect(unsigned int stageNum, float s, float t);
public:
s32 Position[3];
u8 Color[2][4];
float Uv[8][2];
float Lod[8];
void Init();
void Draw();
void SetRegColor(int reg, int comp, bool konst, s16 color);
enum { RED_C, GRN_C, BLU_C, ALP_C };
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _OPCODEDECODER_H_
#define _OPCODEDECODER_H_
#include "Common.h"
namespace TextureEncoder
{
void Encode(u8 *dest_ptr);
}
#endif

View File

@ -0,0 +1,150 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "TextureSampler.h"
#include "Main.h"
#include "BPMemLoader.h"
#include "../../../Core/VideoCommon/Src/TextureDecoder.h"
#include <cmath>
namespace TextureSampler
{
inline int iround(float x)
{
int t;
__asm
{
fld x
fistp t
}
return t;
}
inline void WrapCoord(int &coord, int wrapMode, int imageSize)
{
switch (wrapMode)
{
case 0: // clamp
coord = (coord>imageSize)?imageSize:(coord<0)?0:coord;
break;
case 1: // wrap
coord = coord % (imageSize + 1);
coord = (coord<0)?imageSize+coord:coord;
break;
case 2: // mirror
{
int sizePlus1 = imageSize + 1;
int div = coord / sizePlus1;
coord = coord - (div * sizePlus1);
coord = (coord<0)?-coord:coord;
coord = (div&1)?imageSize - coord:coord;
}
break;
}
}
inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract)
{
outTexel[0] = inTexel[0] * fract;
outTexel[1] = inTexel[1] * fract;
outTexel[2] = inTexel[2] * fract;
outTexel[3] = inTexel[3] * fract;
}
inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract)
{
outTexel[0] += inTexel[0] * fract;
outTexel[1] += inTexel[1] * fract;
outTexel[2] += inTexel[2] * fract;
outTexel[3] += inTexel[3] * fract;
}
void Sample(float s, float t, float lod, u8 texmap, u8 *sample)
{
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
u8 subTexmap = texmap & 3;
TexMode0& tm0 = texUnit.texMode0[subTexmap];
TexImage0& ti0 = texUnit.texImage0[subTexmap];
TexTLUT& texTlut = texUnit.texTlut[subTexmap];
u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5;
u8 *imageSrc = g_VideoInitialize.pGetMemoryPointer(imageBase);
bool linear = false;
if (lod > 0 && tm0.min_filter > 4 || lod <= 0 && tm0.mag_filter)
linear = true;
if (linear)
{
s32 s256 = s32((s - 0.5f) * 256);
s32 t256 = s32((t- 0.5f) * 256);
int imageS = s256 >> 8;
int imageSPlus1 = imageS + 1;
u32 fractS = s256 & 0xff;
fractS += fractS >> 7;
int imageT = t256 >> 8;
int imageTPlus1 = imageT + 1;
u32 fractT = t256 & 0xff;
fractT += fractT >> 7;
u8 sampledTex[4];
u32 texel[4];
WrapCoord(imageS, tm0.wrap_s, ti0.width);
WrapCoord(imageT, tm0.wrap_t, ti0.height);
WrapCoord(imageSPlus1, tm0.wrap_s, ti0.width);
WrapCoord(imageTPlus1, tm0.wrap_t, ti0.height);
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
SetTexel(sampledTex, texel, (256 - fractS) * (256 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
AddTexel(sampledTex, texel, (fractS) * (256 - fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
AddTexel(sampledTex, texel, (256 - fractS) * (fractT));
TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
AddTexel(sampledTex, texel, (fractS) * (fractT));
sample[0] = (u8)(texel[0] >> 16);
sample[1] = (u8)(texel[1] >> 16);
sample[2] = (u8)(texel[2] >> 16);
sample[3] = (u8)(texel[3] >> 16);
}
else
{
int imageS = int(s);
int imageT = int(t);
WrapCoord(imageS, tm0.wrap_s, ti0.width);
WrapCoord(imageT, tm0.wrap_t, ti0.height);
TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, ti0.width, ti0.format, texTlut.tmem_offset << 9, texTlut.tlut_format);
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TEXTURESAMPLER_H_
#define _TEXTURESAMPLER_H_
#include "Common.h"
namespace TextureSampler
{
void Sample(float s, float t, float lod, u8 texmap, u8 *sample);
}
#endif

View File

@ -0,0 +1,486 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include <math.h>
#include "TransformUnit.h"
#include "XFMemLoader.h"
#include "CPMemLoader.h"
#include "NativeVertexFormat.h"
#include "../../Plugin_VideoDX9/Src/Vec3.h"
namespace TransformUnit
{
void MultiplyVec2Mat24(const float *vec, const float *mat, float *result)
{
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] + mat[3];
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] + mat[7];
}
void MultiplyVec2Mat34(const float *vec, const float *mat, float *result)
{
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] + mat[3];
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] + mat[7];
result[2] = mat[8] * vec[0] + mat[9] * vec[1] + mat[10] + mat[11];
}
void MultiplyVec3Mat33(const float *vec, const float *mat, float *result)
{
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] * vec[2];
result[1] = mat[3] * vec[0] + mat[4] * vec[1] + mat[5] * vec[2];
result[2] = mat[6] * vec[0] + mat[7] * vec[1] + mat[8] * vec[2];
}
void MultiplyVec3Mat34(const float *vec, const float *mat, float *result)
{
result[0] = mat[0] * vec[0] + mat[1] * vec[1] + mat[2] * vec[2] + mat[3];
result[1] = mat[4] * vec[0] + mat[5] * vec[1] + mat[6] * vec[2] + mat[7];
result[2] = mat[8] * vec[0] + mat[9] * vec[1] + mat[10] * vec[2] + mat[11];
}
void MultipleVec3Perspective(const float *vec, const float *proj, float *result)
{
result[0] = proj[0] * vec[0] + proj[1] * vec[2];
result[1] = proj[2] * vec[1] + proj[3] * vec[2];
//result[2] = (proj[4] * vec[2] + proj[5]);
result[2] = (proj[4] * vec[2] + proj[5]) * (1.0f - (float)1e-7);
result[3] = -vec[2];
}
void MultipleVec3Ortho(const float *vec, const float *proj, float *result)
{
result[0] = proj[0] * vec[0] + proj[1];
result[1] = proj[2] * vec[1] + proj[3];
result[2] = proj[4] * vec[2] + proj[5];
result[3] = 1;
}
void TransformPosition(const InputVertexData *src, OutputVertexData *dst)
{
const float* mat = (const float*)&xfregs.posMatrices[src->posMtx * 4];
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
if (xfregs.projection[6] == 0)
{
MultipleVec3Perspective(dst->mvPosition, xfregs.projection, dst->projectedPosition);
}
else
{
MultipleVec3Ortho(dst->mvPosition, xfregs.projection, dst->projectedPosition);
}
}
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst)
{
const float* mat = (const float*)&xfregs.normalMatrices[(src->posMtx & 31) * 3];
if (nbt)
{
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
MultiplyVec3Mat33(src->normal[1], mat, dst->normal[1]);
MultiplyVec3Mat33(src->normal[2], mat, dst->normal[2]);
Vec3 *norm0 = (Vec3*)dst->normal[0];
norm0->normalize();
}
else
{
MultiplyVec3Mat33(src->normal[0], mat, dst->normal[0]);
Vec3 *norm0 = (Vec3*)dst->normal[0];
norm0->normalize();
}
}
inline void TransformTexCoordRegular(const TexMtxInfo &texinfo, int coordNum, const InputVertexData *srcVertex, OutputVertexData *dstVertex)
{
const float *src;
switch (texinfo.sourcerow)
{
case XF_SRCGEOM_INROW:
src = srcVertex->position;
break;
case XF_SRCNORMAL_INROW:
src = srcVertex->normal[0];
break;
case XF_SRCBINORMAL_T_INROW:
src = srcVertex->normal[1];
break;
case XF_SRCBINORMAL_B_INROW:
src = srcVertex->normal[2];
break;
default:
_assert_(texinfo.sourcerow >= XF_SRCTEX0_INROW && texinfo.sourcerow <= XF_SRCTEX7_INROW);
src = srcVertex->texCoords[texinfo.sourcerow - XF_SRCTEX0_INROW];
break;
}
const float *mat = (const float*)&xfregs.posMatrices[srcVertex->texMtx[coordNum] * 4];
float *dst = dstVertex->texCoords[coordNum];
if (texinfo.inputform == XF_TEXINPUT_AB11)
{
MultiplyVec2Mat34(src, mat, dst);
}
else
{
MultiplyVec3Mat34(src, mat, dst);
}
if (xfregs.dualTexTrans)
{
float tempCoord[3];
// normalize
const PostMtxInfo &postInfo = xfregs.postMtxInfo[coordNum];
if (postInfo.normalize)
{
float length = sqrtf(dst[0] * dst[0] + dst[1] * dst[1] + dst[2] * dst[2]);
float invL = 1.0f / length;
tempCoord[0] = invL * dst[0];
tempCoord[1] = invL * dst[1];
tempCoord[2] = invL * dst[2];
}
else
{
tempCoord[0] = dst[0];
tempCoord[1] = dst[1];
tempCoord[2] = dst[2];
}
const float *postMat = (const float*)&xfregs.postMatrices[postInfo.index * 4];
MultiplyVec3Mat34(tempCoord, postMat, dst);
}
}
struct LightPointer
{
u32 reserved[3];
u8 color[4];
Vec3 cosatt;
Vec3 distatt;
Vec3 pos;
Vec3 dir;
};
inline void AddIntegerColor(const u8 *src, Vec3 &dst)
{
dst.x += src[1];
dst.y += src[2];
dst.z += src[3];
}
inline void AddScaledIntegerColor(const u8 *src, float scale, Vec3 &dst)
{
dst.x += src[1] * scale;
dst.y += src[2] * scale;
dst.z += src[3] * scale;
}
inline float Clamp(float val, float a, float b)
{
return val<a?a:val>b?b:val;
}
void LightColor(const float *vertexPos, const float *normal, u8 lightNum, const LitChannel &chan, Vec3 &lightCol)
{
// must be the size of 3 32bit floats for the light pointer to be valid
_assert_(sizeof(Vec3) == 12);
const Vec3 *pos = (const Vec3*)vertexPos;
const Vec3 *norm0 = (const Vec3*)normal;
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*lightNum];
if (!(chan.attnfunc & 1)) {
// atten disabled
switch (chan.diffusefunc) {
case LIGHTDIF_NONE:
AddIntegerColor(light->color, lightCol);
break;
case LIGHTDIF_SIGN:
{
Vec3 ldir = (light->pos - *pos).normalized();
float diffuse = ldir * (*norm0);
AddScaledIntegerColor(light->color, diffuse, lightCol);
}
break;
case LIGHTDIF_CLAMP:
{
Vec3 ldir = (light->pos - *pos).normalized();
float diffuse = max(0.0f, ldir * (*norm0));
AddScaledIntegerColor(light->color, diffuse, lightCol);
}
break;
default: _assert_(0);
}
}
else { // spec and spot
// not sure about divide by zero checks
Vec3 ldir = light->pos - *pos;
float attn;
if (chan.attnfunc == 3) { // spot
float dist2 = ldir.length2();
float dist = sqrtf(dist2);
ldir = ldir / dist;
attn = max(0.0f, ldir * light->dir);
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
attn = distAtt==0.0f?0.0f:(max(0.0f, cosAtt) / distAtt);
}
else if (chan.attnfunc == 1) { // specular
attn = (light->pos * (*norm0)) > 0 ? max(0.0f, (light->dir * (*norm0))) : 0;
ldir.set(1.0f, attn, attn * attn);
float cosAtt = light->cosatt * ldir;
float distAtt = light->distatt * ldir;
attn = distAtt==0.0f?1.0f:(max(0.0f, cosAtt) / distAtt);
}
switch (chan.diffusefunc) {
case LIGHTDIF_NONE:
AddScaledIntegerColor(light->color, attn, lightCol);
break;
case LIGHTDIF_SIGN:
{
float difAttn = ldir * (*norm0);
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
}
break;
case LIGHTDIF_CLAMP:
{
float difAttn = max(0.0f, ldir * (*norm0));
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
}
break;
default: _assert_(0);
}
}
}
void LightAlpha(const float *vertexPos, const float *normal, u8 lightNum, const LitChannel &chan, float &lightCol)
{
// must be the size of 3 32bit floats for the light pointer to be valid
_assert_(sizeof(Vec3) == 12);
const Vec3 *pos = (const Vec3*)vertexPos;
const Vec3 *norm0 = (const Vec3*)normal;
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*lightNum];
if (!(chan.attnfunc & 1)) {
// atten disabled
switch (chan.diffusefunc) {
case LIGHTDIF_NONE:
lightCol += light->color[0];
break;
case LIGHTDIF_SIGN:
{
Vec3 ldir = (light->pos - *pos).normalized();
float diffuse = ldir * (*norm0);
lightCol += light->color[0] * diffuse;
}
break;
case LIGHTDIF_CLAMP:
{
Vec3 ldir = (light->pos - *pos).normalized();
float diffuse = max(0.0f, ldir * (*norm0));
lightCol += light->color[0] * diffuse;
}
break;
default: _assert_(0);
}
}
else { // spec and spot
Vec3 ldir = light->pos - *pos;
float attn;
if (chan.attnfunc == 3) { // spot
float dist2 = ldir.length2();
float dist = sqrtf(dist2);
ldir = ldir / dist;
attn = max(0.0f, ldir * light->dir);
float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn);
float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
attn = distAtt==0.0f?0.0f:(max(0.0f, cosAtt) / distAtt);
}
else if (chan.attnfunc == 1) { // specular
attn = (light->pos * (*norm0)) > 0 ? max(0.0f, (light->dir * (*norm0))) : 0;
ldir.set(1.0f, attn, attn * attn);
float cosAtt = light->cosatt * ldir;
float distAtt = light->distatt * ldir;
attn = distAtt==0.0f?1.0f:(max(0.0f, cosAtt) / distAtt);
}
switch (chan.diffusefunc) {
case LIGHTDIF_NONE:
lightCol += light->color[0] * attn;
break;
case LIGHTDIF_SIGN:
{
float difAttn = ldir * (*norm0);
lightCol += light->color[0] * attn * difAttn;
}
break;
case LIGHTDIF_CLAMP:
{
float difAttn = max(0.0f, ldir * (*norm0));
lightCol += light->color[0] * attn * difAttn;
}
break;
default: _assert_(0);
}
}
}
void TransformColor(const InputVertexData *src, OutputVertexData *dst)
{
for (u32 chan = 0; chan < xfregs.nNumChans; chan++)
{
// abgr
u8 matcolor[4];
u8 chancolor[4];
// color
LitChannel &colorchan = xfregs.color[chan];
if (colorchan.matsource)
*(u32*)matcolor = *(u32*)src->color[chan]; // vertex
else
*(u32*)matcolor = xfregs.matColor[chan];
if (colorchan.enablelighting)
{
Vec3 lightCol;
if (colorchan.ambsource)
{
// vertex
lightCol.x = src->color[chan][1];
lightCol.y = src->color[chan][2];
lightCol.z = src->color[chan][3];
}
else
{
u8 *ambColor = (u8*)&xfregs.ambColor[chan];
lightCol.x = ambColor[1];
lightCol.y = ambColor[2];
lightCol.z = ambColor[3];
}
u8 mask = colorchan.GetFullLightMask();
for (int i = 0; i < 8; ++i) {
if (mask&(1<<i))
LightColor(dst->mvPosition, dst->normal[0], i, colorchan, lightCol);
}
float inv = 1.0f / 255.0f;
chancolor[1] = (u8)(matcolor[1] * Clamp(lightCol.x * inv, 0.0f, 1.0f));
chancolor[2] = (u8)(matcolor[2] * Clamp(lightCol.y * inv, 0.0f, 1.0f));
chancolor[3] = (u8)(matcolor[3] * Clamp(lightCol.z * inv, 0.0f, 1.0f));
}
else
{
*(u32*)chancolor = *(u32*)matcolor;
}
// alpha
LitChannel &alphachan = xfregs.alpha[chan];
if (alphachan.matsource)
matcolor[0] = src->color[chan][0]; // vertex
else
matcolor[0] = xfregs.matColor[chan] & 0xff;
if (xfregs.alpha[chan].enablelighting)
{
float lightCol;
if (alphachan.ambsource)
lightCol = src->color[chan][0]; // vertex
else
lightCol = (float)(xfregs.ambColor[chan] & 0xff);
u8 mask = alphachan.GetFullLightMask();
for (int i = 0; i < 8; ++i) {
if (mask&(1<<i))
LightAlpha(dst->mvPosition, dst->normal[0], i, alphachan, lightCol);
}
chancolor[0] = (u8)(matcolor[0] * Clamp(lightCol / 255.0f, 0.0f, 1.0f));
}
else
{
chancolor[0] = matcolor[0];
}
// abgr -> rgba
*(u32*)dst->color[chan] = Common::swap32(*(u32*)chancolor);
}
}
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst)
{
for (u32 coordNum = 0; coordNum < xfregs.numTexGens; coordNum++)
{
const TexMtxInfo &texinfo = xfregs.texMtxInfo[coordNum];
switch (texinfo.texgentype)
{
case XF_TEXGEN_REGULAR:
TransformTexCoordRegular(texinfo, coordNum, src, dst);
break;
case XF_TEXGEN_EMBOSS_MAP:
{
const Vec3 *pos = (const Vec3*)dst->mvPosition;
const Vec3 *norm1 = (const Vec3*)dst->normal[1];
const Vec3 *norm2 = (const Vec3*)dst->normal[2];
const LightPointer *light = (const LightPointer*)&xfregs.lights[0x10*texinfo.embosslightshift];
Vec3 ldir = (light->pos - *pos).normalized();
float d1 = ldir * (*norm1);
float d2 = ldir * (*norm2);
dst->texCoords[coordNum][0] = dst->texCoords[texinfo.embosssourceshift][0] + d1;
dst->texCoords[coordNum][1] = dst->texCoords[texinfo.embosssourceshift][1] + d2;
dst->texCoords[coordNum][2] = dst->texCoords[texinfo.embosssourceshift][2];
}
break;
case XF_TEXGEN_COLOR_STRGBC0:
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
dst->texCoords[coordNum][0] = (float)dst->color[0][0] / 255.0f;
dst->texCoords[coordNum][1] = (float)dst->color[0][1] / 255.0f;
dst->texCoords[coordNum][2] = 1.0f;
break;
case XF_TEXGEN_COLOR_STRGBC1:
_assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW);
_assert_(texinfo.inputform == XF_TEXINPUT_AB11);
dst->texCoords[coordNum][0] = (float)dst->color[1][0] / 255.0f;
dst->texCoords[coordNum][1] = (float)dst->color[1][1] / 255.0f;
dst->texCoords[coordNum][2] = 1.0f;
break;
default:
ERROR_LOG(VIDEO, "Bad tex gen type %i", texinfo.texgentype);
}
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _TRANSFORM_UNIT_H_
#define _TRANSFORM_UNIT_H_
struct InputVertexData;
struct OutputVertexData;
namespace TransformUnit
{
void MultiplyVec2Mat24(const float *vec, const float *mat, float *result);
void MultiplyVec2Mat34(const float *vec, const float *mat, float *result);
void MultiplyVec3Mat33(const float *vec, const float *mat, float *result);
void MultiplyVec3Mat34(const float *vec, const float *mat, float *result);
void TransformPosition(const InputVertexData *src, OutputVertexData *dst);
void TransformNormal(const InputVertexData *src, bool nbt, OutputVertexData *dst);
void TransformColor(const InputVertexData *src, OutputVertexData *dst);
void TransformTexCoord(const InputVertexData *src, OutputVertexData *dst);
}
#endif

View File

@ -0,0 +1,75 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "VertexFormatConverter.h"
namespace VertexFormatConverter
{
void LoadNormal1_Byte(InputVertexData *dst, u8 *src)
{
dst->normal[0][0] = (float)(s8)src[0] / 128;
dst->normal[0][1] = (float)(s8)src[1] / 128;
dst->normal[0][2] = (float)(s8)src[2] / 128;
}
void LoadNormal1_Short(InputVertexData *dst, u8 *src)
{
dst->normal[0][0] = (float)((s16*)src)[0] / 32768;
dst->normal[0][1] = (float)((s16*)src)[1] / 32768;
dst->normal[0][2] = (float)((s16*)src)[2] / 32768;
}
void LoadNormal1_Float(InputVertexData *dst, u8 *src)
{
dst->normal[0][0] = ((float*)src)[0];
dst->normal[0][1] = ((float*)src)[1];
dst->normal[0][2] = ((float*)src)[2];
}
void LoadNormal3_Byte(InputVertexData *dst, u8 *src)
{
for (int i = 0, j = 0; i < 3; i++, j+=3)
{
dst->normal[i][0] = (float)(s8)src[j + 0] / 128;
dst->normal[i][1] = (float)(s8)src[j + 1] / 128;
dst->normal[i][2] = (float)(s8)src[j + 2] / 128;
}
}
void LoadNormal3_Short(InputVertexData *dst, u8 *src)
{
for (int i = 0, j = 0; i < 3; i++, j+=3)
{
dst->normal[i][0] = (float)((s16*)src)[j + 0] / 32768;
dst->normal[i][1] = (float)((s16*)src)[j + 1] / 32768;
dst->normal[i][2] = (float)((s16*)src)[j + 2] / 32768;
}
}
void LoadNormal3_Float(InputVertexData *dst, u8 *src)
{
for (int i = 0, j = 0; i < 3; i++, j+=3)
{
dst->normal[i][0] = ((float*)src)[j + 0];
dst->normal[i][1] = ((float*)src)[j + 1];
dst->normal[i][2] = ((float*)src)[j + 2];
}
}
}

View File

@ -0,0 +1,35 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXFORMATCONVERTER_H
#define _VERTEXFORMATCONVERTER_H
#include "NativeVertexFormat.h"
namespace VertexFormatConverter
{
typedef void (*NormalConverter)(InputVertexData*, u8*);
void LoadNormal1_Byte(InputVertexData *dst, u8 *src);
void LoadNormal1_Short(InputVertexData *dst, u8 *src);
void LoadNormal1_Float(InputVertexData *dst, u8 *src);
void LoadNormal3_Byte(InputVertexData *dst, u8 *src);
void LoadNormal3_Short(InputVertexData *dst, u8 *src);
void LoadNormal3_Float(InputVertexData *dst, u8 *src);
}
#endif

View File

@ -0,0 +1,403 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "VertexLoader.h"
#include "VertexLoader_Position.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Normal.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Color.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_TextCoord.h"
#include "CPMemLoader.h"
#include "XFMemLoader.h"
#include "TransformUnit.h"
#include "SetupUnit.h"
#include "Statistics.h"
#include "NativeVertexWriter.h"
#include "VertexFormatConverter.h"
#include "../../../Core/VideoCommon/Src/DataReader.h"
// Vertex loaders read these
int tcIndex;
int colIndex;
int colElements[2];
float posScale;
float tcScale[8];
VertexLoader::VertexLoader() :
m_VertexSize(0),
m_NumAttributeLoaders(0)
{
VertexLoader_Normal::Init();
m_SetupUnit = new SetupUnit;
}
VertexLoader::~VertexLoader()
{
delete m_SetupUnit;
m_SetupUnit = NULL;
}
void VertexLoader::SetFormat(u8 attributeIndex, u8 primitiveType)
{
m_CurrentVat = &g_VtxAttr[attributeIndex];
posScale = 1.0f / float(1 << m_CurrentVat->g0.PosFrac);
tcScale[0] = 1.0f / float(1 << m_CurrentVat->g0.Tex0Frac);
tcScale[1] = 1.0f / float(1 << m_CurrentVat->g1.Tex1Frac);
tcScale[2] = 1.0f / float(1 << m_CurrentVat->g1.Tex2Frac);
tcScale[3] = 1.0f / float(1 << m_CurrentVat->g1.Tex3Frac);
tcScale[4] = 1.0f / float(1 << m_CurrentVat->g2.Tex4Frac);
tcScale[5] = 1.0f / float(1 << m_CurrentVat->g2.Tex5Frac);
tcScale[6] = 1.0f / float(1 << m_CurrentVat->g2.Tex6Frac);
tcScale[7] = 1.0f / float(1 << m_CurrentVat->g2.Tex7Frac);
//TexMtx
const int tmDesc[8] = {
g_VtxDesc.Tex0MatIdx, g_VtxDesc.Tex1MatIdx, g_VtxDesc.Tex2MatIdx, g_VtxDesc.Tex3MatIdx,
g_VtxDesc.Tex4MatIdx, g_VtxDesc.Tex5MatIdx, g_VtxDesc.Tex6MatIdx, g_VtxDesc.Tex7MatIdx
};
// Colors
const int colDesc[2] = {g_VtxDesc.Color0, g_VtxDesc.Color1};
colElements[0] = m_CurrentVat->g0.Color0Elements;
colElements[1] = m_CurrentVat->g0.Color1Elements;
const int colComp[2] = {m_CurrentVat->g0.Color0Comp, m_CurrentVat->g0.Color1Comp};
// TextureCoord
const int tcDesc[8] = {
g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord,
g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (g_VtxDesc.Hex >> 31) & 3
};
const int tcElements[8] = {
m_CurrentVat->g0.Tex0CoordElements, m_CurrentVat->g1.Tex1CoordElements, m_CurrentVat->g1.Tex2CoordElements,
m_CurrentVat->g1.Tex3CoordElements, m_CurrentVat->g1.Tex4CoordElements, m_CurrentVat->g2.Tex5CoordElements,
m_CurrentVat->g2.Tex6CoordElements, m_CurrentVat->g2.Tex7CoordElements
};
const int tcFormat[8] = {
m_CurrentVat->g0.Tex0CoordFormat, m_CurrentVat->g1.Tex1CoordFormat, m_CurrentVat->g1.Tex2CoordFormat,
m_CurrentVat->g1.Tex3CoordFormat, m_CurrentVat->g1.Tex4CoordFormat, m_CurrentVat->g2.Tex5CoordFormat,
m_CurrentVat->g2.Tex6CoordFormat, m_CurrentVat->g2.Tex7CoordFormat
};
m_VertexSize = 0;
// Reset pipeline
m_positionLoader = NULL;
m_normalLoader = NULL;
m_NumAttributeLoaders = 0;
// Reset vertex
// matrix index from xfregs or cp memory?
_assert_msg_(VIDEO, xfregs.MatrixIndexA.PosNormalMtxIdx == MatrixIndexA.PosNormalMtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex0MtxIdx == MatrixIndexA.Tex0MtxIdx, "Matrix indices don't match");
//_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex1MtxIdx == MatrixIndexA.Tex1MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex2MtxIdx == MatrixIndexA.Tex2MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexA.Tex3MtxIdx == MatrixIndexA.Tex3MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex4MtxIdx == MatrixIndexB.Tex4MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex5MtxIdx == MatrixIndexB.Tex5MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex6MtxIdx == MatrixIndexB.Tex6MtxIdx, "Matrix indices don't match");
_assert_msg_(VIDEO, xfregs.MatrixIndexB.Tex7MtxIdx == MatrixIndexB.Tex7MtxIdx, "Matrix indices don't match");
m_Vertex.posMtx = xfregs.MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = xfregs.MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = xfregs.MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = xfregs.MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = xfregs.MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = xfregs.MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = xfregs.MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = xfregs.MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = xfregs.MatrixIndexB.Tex7MtxIdx;
/*m_Vertex.posMtx = MatrixIndexA.PosNormalMtxIdx;
m_Vertex.texMtx[0] = MatrixIndexA.Tex0MtxIdx;
m_Vertex.texMtx[1] = MatrixIndexA.Tex1MtxIdx;
m_Vertex.texMtx[2] = MatrixIndexA.Tex2MtxIdx;
m_Vertex.texMtx[3] = MatrixIndexA.Tex3MtxIdx;
m_Vertex.texMtx[4] = MatrixIndexB.Tex4MtxIdx;
m_Vertex.texMtx[5] = MatrixIndexB.Tex5MtxIdx;
m_Vertex.texMtx[6] = MatrixIndexB.Tex6MtxIdx;
m_Vertex.texMtx[7] = MatrixIndexB.Tex7MtxIdx;*/
if (g_VtxDesc.PosMatIdx != NOT_PRESENT) {
AddAttributeLoader(LoadPosMtx);
m_VertexSize++;
}
for (int i = 0; i < 8; ++i) {
if (tmDesc[i] != NOT_PRESENT)
{
AddAttributeLoader(LoadTexMtx, i);
m_VertexSize++;
}
}
switch (g_VtxDesc.Position) {
case NOT_PRESENT: {_assert_msg_(VIDEO, 0, "Vertex descriptor without position!"); } break;
case DIRECT:
switch (m_CurrentVat->g0.PosFormat) {
case FORMAT_UBYTE: m_VertexSize += m_CurrentVat->g0.PosElements?3:2; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_UByte3:Pos_ReadDirect_UByte2); break;
case FORMAT_BYTE: m_VertexSize += m_CurrentVat->g0.PosElements?3:2; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Byte3:Pos_ReadDirect_Byte2); break;
case FORMAT_USHORT: m_VertexSize += m_CurrentVat->g0.PosElements?6:4; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_UShort3:Pos_ReadDirect_UShort2); break;
case FORMAT_SHORT: m_VertexSize += m_CurrentVat->g0.PosElements?6:4; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Short3:Pos_ReadDirect_Short2); break;
case FORMAT_FLOAT: m_VertexSize += m_CurrentVat->g0.PosElements?12:8; m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadDirect_Float3:Pos_ReadDirect_Float2); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadPosition);
break;
case INDEX8:
switch (m_CurrentVat->g0.PosFormat) {
case FORMAT_UBYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_UByte3:Pos_ReadIndex8_UByte2); break;
case FORMAT_BYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Byte3:Pos_ReadIndex8_Byte2); break;
case FORMAT_USHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_UShort3:Pos_ReadIndex8_UShort2); break;
case FORMAT_SHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Short3:Pos_ReadIndex8_Short2); break;
case FORMAT_FLOAT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex8_Float3:Pos_ReadIndex8_Float2); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadPosition);
m_VertexSize += 1;
break;
case INDEX16:
switch (m_CurrentVat->g0.PosFormat) {
case FORMAT_UBYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_UByte3:Pos_ReadIndex16_UByte2); break;
case FORMAT_BYTE: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Byte3:Pos_ReadIndex16_Byte2); break;
case FORMAT_USHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_UShort3:Pos_ReadIndex16_UShort2); break;
case FORMAT_SHORT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Short3:Pos_ReadIndex16_Short2); break;
case FORMAT_FLOAT: m_positionLoader = (m_CurrentVat->g0.PosElements?Pos_ReadIndex16_Float3:Pos_ReadIndex16_Float2); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadPosition);
m_VertexSize += 2;
break;
}
// Normals
if (g_VtxDesc.Normal != NOT_PRESENT) {
m_VertexSize += VertexLoader_Normal::GetSize(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3);
m_normalLoader = VertexLoader_Normal::GetFunction(g_VtxDesc.Normal, m_CurrentVat->g0.NormalFormat, m_CurrentVat->g0.NormalElements, m_CurrentVat->g0.NormalIndex3, true);
if (m_normalLoader == 0)
{
ERROR_LOG(VIDEO, "VertexLoader_Normal::GetFunction returned zero!");
}
AddAttributeLoader(LoadNormal);
switch (m_CurrentVat->g0.NormalFormat) {
case FORMAT_UBYTE:
case FORMAT_BYTE:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Byte;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Byte;
break;
case FORMAT_USHORT:
case FORMAT_SHORT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Short;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Short;
break;
case FORMAT_FLOAT:
if (m_CurrentVat->g0.NormalElements)
m_normalConverter = VertexFormatConverter::LoadNormal3_Float;
else
m_normalConverter = VertexFormatConverter::LoadNormal1_Float;
break;
default: _assert_(0); break;
}
}
for (int i = 0; i < 2; i++) {
switch (colDesc[i])
{
case NOT_PRESENT:
m_colorLoader[i] = NULL;
break;
case DIRECT:
switch (colComp[i])
{
case FORMAT_16B_565: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_565); break;
case FORMAT_24B_888: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_888); break;
case FORMAT_32B_888x: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_888x); break;
case FORMAT_16B_4444: m_VertexSize += 2; m_colorLoader[i] = (Color_ReadDirect_16b_4444); break;
case FORMAT_24B_6666: m_VertexSize += 3; m_colorLoader[i] = (Color_ReadDirect_24b_6666); break;
case FORMAT_32B_8888: m_VertexSize += 4; m_colorLoader[i] = (Color_ReadDirect_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX8:
m_VertexSize += 1;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex8_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex8_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex8_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex8_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex8_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex8_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
case INDEX16:
m_VertexSize += 2;
switch (colComp[i])
{
case FORMAT_16B_565: m_colorLoader[i] = (Color_ReadIndex16_16b_565); break;
case FORMAT_24B_888: m_colorLoader[i] = (Color_ReadIndex16_24b_888); break;
case FORMAT_32B_888x: m_colorLoader[i] = (Color_ReadIndex16_32b_888x); break;
case FORMAT_16B_4444: m_colorLoader[i] = (Color_ReadIndex16_16b_4444); break;
case FORMAT_24B_6666: m_colorLoader[i] = (Color_ReadIndex16_24b_6666); break;
case FORMAT_32B_8888: m_colorLoader[i] = (Color_ReadIndex16_32b_8888); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadColor, i);
break;
}
}
// Texture matrix indices (remove if corresponding texture coordinate isn't enabled)
for (int i = 0; i < 8; i++) {
int elements = tcElements[i];
switch (tcDesc[i])
{
case NOT_PRESENT:
m_texCoordLoader[i] = NULL;
break;
case DIRECT:
switch (tcFormat[i])
{
case FORMAT_UBYTE: m_VertexSize += elements?2:1; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_UByte2:TexCoord_ReadDirect_UByte1); break;
case FORMAT_BYTE: m_VertexSize += elements?2:1; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Byte2:TexCoord_ReadDirect_Byte1); break;
case FORMAT_USHORT: m_VertexSize += elements?4:2; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_UShort2:TexCoord_ReadDirect_UShort1); break;
case FORMAT_SHORT: m_VertexSize += elements?4:2; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Short2:TexCoord_ReadDirect_Short1); break;
case FORMAT_FLOAT: m_VertexSize += elements?8:4; m_texCoordLoader[i] = (elements?TexCoord_ReadDirect_Float2:TexCoord_ReadDirect_Float1); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadTexCoord, i);
break;
case INDEX8:
m_VertexSize += 1;
switch (tcFormat[i])
{
case FORMAT_UBYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_UByte2:TexCoord_ReadIndex8_UByte1); break;
case FORMAT_BYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Byte2:TexCoord_ReadIndex8_Byte1); break;
case FORMAT_USHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_UShort2:TexCoord_ReadIndex8_UShort1); break;
case FORMAT_SHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Short2:TexCoord_ReadIndex8_Short1); break;
case FORMAT_FLOAT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex8_Float2:TexCoord_ReadIndex8_Float1); break;
default: _assert_(0); break;
}
AddAttributeLoader(LoadTexCoord, i);
break;
case INDEX16:
m_VertexSize += 2;
switch (tcFormat[i])
{
case FORMAT_UBYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_UByte2:TexCoord_ReadIndex16_UByte1); break;
case FORMAT_BYTE: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Byte2:TexCoord_ReadIndex16_Byte1); break;
case FORMAT_USHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_UShort2:TexCoord_ReadIndex16_UShort1); break;
case FORMAT_SHORT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Short2:TexCoord_ReadIndex16_Short1); break;
case FORMAT_FLOAT: m_texCoordLoader[i] = (elements?TexCoord_ReadIndex16_Float2:TexCoord_ReadIndex16_Float1); break;
default: _assert_(0);
}
AddAttributeLoader(LoadTexCoord, i);
break;
}
}
m_SetupUnit->Init(primitiveType);
}
void VertexLoader::LoadVertex()
{
for (int i = 0; i < m_NumAttributeLoaders; i++)
m_AttributeLoaders[i].loader(this, &m_Vertex, m_AttributeLoaders[i].index);
OutputVertexData* outVertex = m_SetupUnit->GetVertex();
// transform input data
TransformUnit::TransformPosition(&m_Vertex, outVertex);
if (g_VtxDesc.Normal != NOT_PRESENT)
{
TransformUnit::TransformNormal(&m_Vertex, m_CurrentVat->g0.NormalElements, outVertex);
}
TransformUnit::TransformColor(&m_Vertex, outVertex);
TransformUnit::TransformTexCoord(&m_Vertex, outVertex);
m_SetupUnit->SetupVertex();
INCSTAT(stats.thisFrame.numVerticesLoaded)
}
void VertexLoader::AddAttributeLoader(AttributeLoader loader, u8 index)
{
_assert_msg_(VIDEO, m_NumAttributeLoaders < 21, "Too many attribute loaders");
m_AttributeLoaders[m_NumAttributeLoaders].loader = loader;
m_AttributeLoaders[m_NumAttributeLoaders++].index = index;
}
void VertexLoader::LoadPosMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
vertex->posMtx = DataReadU8() & 0x3f;
}
void VertexLoader::LoadTexMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
vertex->texMtx[index] = DataReadU8() & 0x3f;
}
void VertexLoader::LoadPosition(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->position;
vertexLoader->m_positionLoader();
}
void VertexLoader::LoadNormal(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused)
{
u8 buffer[3*3*4];
VertexManager::s_pCurBufferPointer = buffer;
vertexLoader->m_normalLoader();
// the common vertex loader loads data as bytes, shorts or floats so an extra step is needed to make it floats
vertexLoader->m_normalConverter(vertex, buffer);
}
void VertexLoader::LoadColor(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
u32 color;
VertexManager::s_pCurBufferPointer = (u8*)&color;
colIndex = index;
vertexLoader->m_colorLoader[index]();
// rgba -> abgr
*(u32*)vertex->color[index] = Common::swap32(color);
}
void VertexLoader::LoadTexCoord(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index)
{
VertexManager::s_pCurBufferPointer = (u8*)&vertex->texCoords[index];
tcIndex = index;
vertexLoader->m_texCoordLoader[index]();
}

View File

@ -0,0 +1,76 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXLOADER_H_
#define _VERTEXLOADER_H_
#include "Common.h"
#include "NativeVertexFormat.h"
#include "VertexFormatConverter.h"
#include "CPMemLoader.h"
class SetupUnit;
class VertexLoader
{
u32 m_VertexSize;
VAT* m_CurrentVat;
TPipelineFunction m_positionLoader;
TPipelineFunction m_normalLoader;
TPipelineFunction m_colorLoader[2];
TPipelineFunction m_texCoordLoader[8];
VertexFormatConverter::NormalConverter m_normalConverter;
InputVertexData m_Vertex;
typedef void (*AttributeLoader)(VertexLoader*, InputVertexData*, u8);
struct AttrLoaderCall
{
AttributeLoader loader;
u8 index;
};
AttrLoaderCall m_AttributeLoaders[1+8+1+1+2+8];
int m_NumAttributeLoaders;
void AddAttributeLoader(AttributeLoader loader, u8 index=0);
// attribute loader functions
static void LoadPosMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
static void LoadTexMtx(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
static void LoadPosition(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
static void LoadNormal(VertexLoader *vertexLoader, InputVertexData *vertex, u8 unused);
static void LoadColor(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
static void LoadTexCoord(VertexLoader *vertexLoader, InputVertexData *vertex, u8 index);
SetupUnit *m_SetupUnit;
public:
VertexLoader();
~VertexLoader();
void SetFormat(u8 attributeIndex, u8 primitiveType);
u32 GetVertexSize() { return m_VertexSize; }
void LoadVertex();
};
#endif

View File

@ -0,0 +1,20 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "NativeVertexFormat.h"
#include "../../../Core/VideoCommon/Src/VertexLoader_Position.h"

View File

@ -0,0 +1,18 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../../../Core/VideoCommon/Src/VideoCommon.h"

View File

@ -0,0 +1,66 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "IniFile.h"
#include "VideoConfig.h"
#include "../../../Core/Core/Src/ConfigManager.h" // FIXME
Config g_Config;
Config::Config()
{
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bShowStats = false;
bDumpTextures = false;
bDumpObjects = false;
bDumpFrames = false;
bHwRasterizer = false;
nFrameSkip = 0;
drawStart = 0;
drawEnd = 100000;
}
void Config::Load()
{
std::string temp;
IniFile iniFile;
iniFile.Load(FULL_CONFIG_DIR "gfx_software.ini");
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
}
void Config::Save()
{
IniFile iniFile;
iniFile.Load(FULL_CONFIG_DIR "gfx_software.ini");
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
iniFile.Save(FULL_CONFIG_DIR "gfx_opengl.ini");
}

View File

@ -0,0 +1,55 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#define _PLUGIN_VIDEOSOFTWARE_CONFIG_H_
#include "Common.h"
#define STATISTICS 1
// NEVER inherit from this class.
struct Config
{
Config();
void Load();
void Save();
// General
bool bFullscreen;
bool bHideCursor;
bool renderToMainframe;
bool bShowStats;
bool bDumpTextures;
bool bDumpObjects;
bool bDumpFrames;
bool bHwRasterizer;
u32 nFrameSkip;
u32 drawStart;
u32 drawEnd;
private:
DISALLOW_COPY_AND_ASSIGN(Config);
};
extern Config g_Config;
#endif // _PLUGIN_VIDEOSOFTWARE_CONFIG_H_

View File

@ -0,0 +1,404 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <windows.h>
#include <wx/wx.h>
#include <wx/filepicker.h>
#include <wx/notebook.h>
#include <wx/dialog.h>
#include <wx/aboutdlg.h>
#include "../VideoConfig.h"
#include "main.h"
#include "Win32.h"
#include "StringUtil.h"
HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX
class wxDLLApp : public wxApp
{
bool OnInit()
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
#endif
// ------------------
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD dwReason, // reason called
LPVOID lpvReserved) // reserved
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
#if defined(HAVE_WX) && HAVE_WX
// Use wxInitialize() if you don't want GUI instead of the following 12 lines
wxSetInstance((HINSTANCE)hinstDLL);
int argc = 0;
char **argv = NULL;
wxEntryStart(argc, argv);
if (!wxTheApp || !wxTheApp->CallOnInit())
return FALSE;
#endif
}
break;
case DLL_PROCESS_DETACH:
#if defined(HAVE_WX) && HAVE_WX
wxEntryCleanup();
#endif
break;
default:
break;
}
g_hInstance = hinstDLL;
return TRUE;
}
// ----------------------
// The rendering window
// ----------------------
namespace EmuWindow
{
HWND m_hWnd = NULL; // The new window that is created here
HWND m_hParent = NULL;
HWND m_hMain = NULL; // The main CPanel
HINSTANCE m_hInstance = NULL;
WNDCLASSEX wndClass;
const TCHAR m_szClassName[] = _T("DolphinEmuWnd");
int g_winstyle;
// ------------------------------------------
/* Invisible cursor option. In the lack of a predefined IDC_BLANK we make
an empty transparent cursor */
// ------------------
HCURSOR hCursor = NULL, hCursorBlank = NULL;
void CreateCursors(HINSTANCE hInstance)
{
BYTE ANDmaskCursor[] = { 0xff };
BYTE XORmaskCursor[] = { 0x00 };
hCursorBlank = CreateCursor(hInstance, 0,0, 1,1, ANDmaskCursor,XORmaskCursor);
hCursor = LoadCursor(NULL, IDC_ARROW);
}
HWND GetWnd()
{
return m_hWnd;
}
HWND GetParentWnd()
{
return m_hParent;
}
HWND GetChildParentWnd()
{
return m_hMain;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
switch( iMsg )
{
case WM_CREATE:
PostMessage(m_hMain, WM_USER, OPENGL_WM_USER_CREATE, (int)m_hParent);
break;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
return 0;
case WM_SYSKEYDOWN:
switch( LOWORD( wParam ))
{
case VK_RETURN:
// Pressing Alt+Enter switch FullScreen/Windowed
if (m_hParent == NULL && !g_Config.renderToMainframe)
{
ToggleFullscreen(hWnd);
return 0;
}
break;
}
break;
case WM_KEYDOWN:
switch( LOWORD( wParam ))
{
case VK_ESCAPE:
if (g_Config.bFullscreen)
{
// Pressing Esc switch to Windowed in Fullscreen mode
ToggleFullscreen(hWnd);
return 0;
}
else if (!g_Config.renderToMainframe)
{
// And stops the emulation when already in Windowed mode
PostMessage(m_hMain, WM_USER, OPENGL_WM_USER_STOP, 0);
}
break;
}
g_VideoInitialize.pKeyPress(LOWORD(wParam), GetAsyncKeyState(VK_SHIFT) != 0, GetAsyncKeyState(VK_CONTROL) != 0);
break;
/* The reason we pick up the WM_MOUSEMOVE is to be able to change this option
during gameplay. The alternative is to load one of the cursors when the plugin
is loaded and go with that. This should only produce a minimal performance hit
because SetCursor is not supposed to actually change the cursor if it's the
same as the one before. */
case WM_MOUSEMOVE:
/* Check rendering mode; child or parent. Then post the mouse moves to the main window
it's nessesary for both the chil dwindow and separate rendering window because
moves over the rendering window do not reach the main program then. */
if (GetParentWnd() == NULL) // Separate rendering window
PostMessage(m_hMain, iMsg, wParam, -1);
else
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
/* To support the separate window rendering we get the message back here. So we basically
only let it pass through Dolphin > Frame.cpp to determine if it should be on or off
and coordinate it with the other settings if nessesary */
case WM_USER:
/* I set wParam to 10 just in case there are other WM_USER events. If we want more
WM_USER cases we would start making wParam or lParam cases */
if (wParam == 10)
{
if (lParam)
SetCursor(hCursor);
else
SetCursor(hCursorBlank);
}
break;
/* Post thes mouse events to the main window, it's nessesary becase in difference to the
keyboard inputs these events only appear here, not in the main WndProc() */
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
PostMessage(GetParentWnd(), iMsg, wParam, lParam);
break;
// This is called when we close the window when we render to a separate window
case WM_CLOSE:
if (m_hParent == NULL)
{
// Simple hack to easily exit without stopping. Hope to fix the stopping errors soon.
ExitProcess(0);
return 0;
}
case WM_DESTROY:
//Shutdown();
//PostQuitMessage( 0 ); // Call WM_QUIT
break;
// Called when a screensaver wants to show up while this window is active
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
break;
}
return DefWindowProc(hWnd, iMsg, wParam, lParam);
}
// This is called from Create()
HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title)
{
wndClass.cbSize = sizeof( wndClass );
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
// To interfer less with SetCursor() later we set this to NULL
//wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndClass.hCursor = NULL;
wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = m_szClassName;
wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
m_hInstance = hInstance;
RegisterClassEx( &wndClass );
CreateCursors(m_hInstance);
// Create child window
if (parent)
{
m_hParent = m_hMain = parent;
m_hWnd = CreateWindow(m_szClassName, title,
WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent, NULL, hInstance, NULL);
ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
}
// Create new separate window
else
{
DWORD style = g_Config.bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW;
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, style, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
// I save this to m_hMain instead of m_hParent because it casused problems otherwise
m_hMain = (HWND)g_VideoInitialize.pWindowHandle;
m_hWnd = CreateWindow(m_szClassName, title,
style,
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
parent, NULL, hInstance, NULL );
g_winstyle = GetWindowLong( m_hWnd, GWL_STYLE );
g_winstyle &= ~WS_MAXIMIZE & ~WS_MINIMIZE; // remove minimize/maximize style
}
return m_hWnd;
}
void ToggleFullscreen(HWND hParent)
{
if (m_hParent == NULL)
{
int w_fs = 640, h_fs = 480;
if (g_Config.bFullscreen)
{
// Get out of fullscreen
g_Config.bFullscreen = false;
RECT rc = {0, 0, w_fs, h_fs};
// FullScreen -> Desktop
ChangeDisplaySettings(NULL, 0);
RECT rcdesktop; // Get desktop resolution
GetWindowRect(GetDesktopWindow(), &rcdesktop);
ShowCursor(TRUE);
int X = (rcdesktop.right-rcdesktop.left)/2 - (rc.right-rc.left)/2;
int Y = (rcdesktop.bottom-rcdesktop.top)/2 - (rc.bottom-rc.top)/2;
// SetWindowPos to the center of the screen
SetWindowPos(hParent, NULL, X, Y, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Set new window style FS -> Windowed
SetWindowLong(hParent, GWL_STYLE, WS_OVERLAPPEDWINDOW);
// Eventually show the window!
EmuWindow::Show();
}
else
{
// Get into fullscreen
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
// Desktop -> FullScreen
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = w_fs;
dmScreenSettings.dmPelsHeight = h_fs;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
return;
// Set new window style -> PopUp
SetWindowLong(hParent, GWL_STYLE, WS_POPUP);
g_Config.bFullscreen = true;
ShowCursor(FALSE);
// SetWindowPos to the upper-left corner of the screen
SetWindowPos(hParent, NULL, 0, 0, w_fs, h_fs, SWP_NOREPOSITION | SWP_NOZORDER);
// Eventually show the window!
EmuWindow::Show();
}
}
}
void Show()
{
ShowWindow(m_hWnd, SW_SHOW);
BringWindowToTop(m_hWnd);
UpdateWindow(m_hWnd);
}
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title)
{
return OpenWindow(hParent, hInstance, 640, 480, title);
}
void Close()
{
DestroyWindow(m_hWnd);
UnregisterClass(m_szClassName, m_hInstance);
}
// ------------------------------------------
// Set the size of the child or main window
// ------------------------------------------
void SetSize(int width, int height)
{
RECT rc = {0, 0, width, height};
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
// Move and resize the window
rc.left = (1280 - w)/2;
rc.right = rc.left + w;
rc.top = (1024 - h)/2;
rc.bottom = rc.top + h;
MoveWindow(m_hWnd, rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top, TRUE);
}
} // EmuWindow

View File

@ -0,0 +1,39 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _WIN32_H_
#define _WIN32_H_
#pragma once
#include "stdafx.h"
namespace EmuWindow
{
extern int g_winstyle;
HWND GetWnd();
HWND GetParentWnd();
HWND GetChildParentWnd();
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title);
void Show();
void Close();
void ToggleFullscreen(HWND hParent);
void SetSize(int displayWidth, int displayHeight);
}
#endif // _WIN32_H_

View File

@ -0,0 +1,73 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../../../Core/VideoCommon/Src/VideoCommon.h"
#include "XFMemLoader.h"
#include "CPMemLoader.h"
#include "Clipper.h"
XFRegisters xfregs;
void InitXFMemory()
{
memset(&xfregs, 0, sizeof(xfregs));
}
void XFWritten(u32 transferSize, u32 baseAddress)
{
u32 topAddress = baseAddress + transferSize;
if (baseAddress <= 0x1026 && topAddress >= 0x1020)
Clipper::SetViewOffset();
}
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData)
{
u32 size = transferSize;
// do not allow writes past registers
if (baseAddress + transferSize > 0x1058)
{
INFO_LOG(VIDEO, "xf load exceeds address space: %x %d bytes\n", baseAddress, transferSize);
if (baseAddress >= 0x1058)
size = 0;
else
size = 0x1058 - baseAddress;
}
if (size > 0) {
memcpy_gc( &((u32*)&xfregs)[baseAddress], pData, size * 4);
XFWritten(transferSize, baseAddress);
}
}
void LoadIndexedXF(u32 val, int array)
{
int index = val >> 16;
int address = val & 0xFFF; //check mask
int size = ((val >> 12) & 0xF) + 1;
//load stuff from array to address in xf mem
u32* xfmem = (u32*)&xfregs;
for (int i = 0; i < size; i++)
xfmem[address + i] = Memory_Read_U32(arraybases[array] + arraystrides[array]*index + i*4);
}

View File

@ -0,0 +1,249 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _XFMEMLOADER_H_
#define _XFMEMLOADER_H_
#include "Common.h"
/////////////
// Lighting
/////////////
#define XF_TEXPROJ_ST 0
#define XF_TEXPROJ_STQ 1
#define XF_TEXINPUT_AB11 0
#define XF_TEXINPUT_ABC1 1
#define XF_TEXGEN_REGULAR 0
#define XF_TEXGEN_EMBOSS_MAP 1 // used when bump mapping
#define XF_TEXGEN_COLOR_STRGBC0 2
#define XF_TEXGEN_COLOR_STRGBC1 3
#define XF_SRCGEOM_INROW 0 // input is abc
#define XF_SRCNORMAL_INROW 1 // input is abc
#define XF_SRCCOLORS_INROW 2
#define XF_SRCBINORMAL_T_INROW 3 // input is abc
#define XF_SRCBINORMAL_B_INROW 4 // input is abc
#define XF_SRCTEX0_INROW 5
#define XF_SRCTEX1_INROW 6
#define XF_SRCTEX2_INROW 7
#define XF_SRCTEX3_INROW 8
#define XF_SRCTEX4_INROW 9
#define XF_SRCTEX5_INROW 10
#define XF_SRCTEX6_INROW 11
#define XF_SRCTEX7_INROW 12
#define GX_SRC_REG 0
#define GX_SRC_VTX 1
struct Light
{
u32 useless[3];
u32 color; //rgba
float a0; //attenuation
float a1;
float a2;
float k0; //k stuff
float k1;
float k2;
union
{
struct {
float dpos[3];
float ddir[3]; // specular lights only
};
struct {
float sdir[3];
float shalfangle[3]; // specular lights only
};
};
};
#define LIGHTDIF_NONE 0
#define LIGHTDIF_SIGN 1
#define LIGHTDIF_CLAMP 2
#define LIGHTATTN_SPEC 0 // specular attenuation
#define LIGHTATTN_SPOT 1 // distance/spotlight attenuation
#define LIGHTATTN_NONE 2
#define LIGHTATTN_DIR 3
union LitChannel
{
struct
{
unsigned matsource : 1;
unsigned enablelighting : 1;
unsigned lightMask0_3 : 4;
unsigned ambsource : 1;
unsigned diffusefunc : 2; // LIGHTDIF_X
unsigned attnfunc : 2; // LIGHTATTN_X
unsigned lightMask4_7 : 4;
unsigned unused : 17;
};
u32 hex;
unsigned int GetFullLightMask() const
{
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
}
};
union INVTXSPEC
{
struct
{
unsigned numcolors : 2;
unsigned numnormals : 2; // 0 - nothing, 1 - just normal, 2 - normals and binormals
unsigned numtextures : 4;
unsigned unused : 24;
};
u32 hex;
};
union TXFMatrixIndexA
{
struct
{
unsigned PosNormalMtxIdx : 6;
unsigned Tex0MtxIdx : 6;
unsigned Tex1MtxIdx : 6;
unsigned Tex2MtxIdx : 6;
unsigned Tex3MtxIdx : 6;
};
struct
{
u32 Hex : 30;
u32 unused : 2;
};
};
union TXFMatrixIndexB
{
struct
{
unsigned Tex4MtxIdx : 6;
unsigned Tex5MtxIdx : 6;
unsigned Tex6MtxIdx : 6;
unsigned Tex7MtxIdx : 6;
};
struct
{
u32 Hex : 24;
u32 unused : 8;
};
};
struct Viewport
{
float wd;
float ht;
float zRange;
float xOrig;
float yOrig;
float farZ;
};
union TexMtxInfo
{
struct
{
unsigned unknown : 1;
unsigned projection : 1; // XF_TEXPROJ_X
unsigned inputform : 2; // XF_TEXINPUT_X
unsigned texgentype : 3; // XF_TEXGEN_X
unsigned sourcerow : 5; // XF_SRCGEOM_X
unsigned embosssourceshift : 3; // what generated texcoord to use
unsigned embosslightshift : 3; // light index that is used
};
u32 hex;
};
union PostMtxInfo
{
struct
{
unsigned index : 6; // base row of dual transform matrix
unsigned unused : 2;
unsigned normalize : 1; // normalize before send operation
};
u32 hex;
};
struct XFRegisters
{
u32 posMatrices[256]; // 0x0000 - 0x00ff
u32 unk0[768]; // 0x0100 - 0x03ff
u32 normalMatrices[96]; // 0x0400 - 0x045f
u32 unk1[160]; // 0x0460 - 0x04ff
u32 postMatrices[256]; // 0x0500 - 0x05ff
u32 lights[128]; // 0x0600 - 0x067f
u32 unk2[2432]; // 0x0680 - 0x0fff
u32 error; // 0x1000
u32 diag; // 0x1001
u32 state0; // 0x1002
u32 state1; // 0x1003
u32 xfClock; // 0x1004
u32 clipDisable; // 0x1005
u32 perf0; // 0x1006
u32 perf1; // 0x1007
INVTXSPEC hostinfo; // 0x1008 number of textures,colors,normals from vertex input
u32 nNumChans; // 0x1009
u32 ambColor[2]; // 0x100a, 0x100b
u32 matColor[2]; // 0x100c, 0x100d
LitChannel color[2]; // 0x100e, 0x100f
LitChannel alpha[2]; // 0x1010, 0x1011
u32 dualTexTrans; // 0x1012
u32 unk3; // 0x1013
u32 unk4; // 0x1014
u32 unk5; // 0x1015
u32 unk6; // 0x1016
u32 unk7; // 0x1017
TXFMatrixIndexA MatrixIndexA; // 0x1018
TXFMatrixIndexB MatrixIndexB; // 0x1019
Viewport viewport; // 0x101a - 0x101f
float projection[7]; // 0x1020 - 0x1026
u32 unk8[24]; // 0x1027 - 0x103e
u32 numTexGens; // 0x103f
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047
u32 unk9[8]; // 0x1048 - 0x104f
PostMtxInfo postMtxInfo[8]; // 0x1050 - 0x1057
};
#define XFMEM_POSMATRICES 0x000
#define XFMEM_POSMATRICES_END 0x100
#define XFMEM_NORMALMATRICES 0x400
#define XFMEM_NORMALMATRICES_END 0x460
#define XFMEM_POSTMATRICES 0x500
#define XFMEM_POSTMATRICES_END 0x600
#define XFMEM_LIGHTS 0x600
#define XFMEM_LIGHTS_END 0x680
extern XFRegisters xfregs;
void InitXFMemory();
void XFWritten(u32 transferSize, u32 baseAddress);
void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData);
void LoadIndexedXF(u32 val, int array);
#endif

View File

@ -0,0 +1,211 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "pluginspecs_video.h"
#include "CommandProcessor.h"
#include "OpcodeDecoder.h"
#include "VideoConfig.h"
#include "PixelEngine.h"
#include "CommandProcessor.h"
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Clipper.h"
#include "Rasterizer.h"
#include "Renderer.h"
#include "../../../Core/VideoCommon/Src/LookUpTables.h"
#include "HwRasterizer.h"
#include "LogManager.h"
#include "EfbInterface.h"
PLUGIN_GLOBALS* globals = NULL;
static volatile bool fifoStateRun = false;
SVideoInitialize g_VideoInitialize;
bool g_SkipFrame;
void GetDllInfo (PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_VIDEO;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin Software Renderer");
#else
sprintf(_PluginInfo->Name, "Dolphin Software Renderer (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals)
{
globals = _pPluginGlobals;
LogManager::SetInstance((LogManager *)globals->logManager);
}
void DllDebugger(HWND _hParent, bool Show)
{
}
void DllConfig(HWND _hParent)
{
}
void Initialize(void *init)
{
SVideoInitialize *_pVideoInitialize = (SVideoInitialize*)init;
g_VideoInitialize = *_pVideoInitialize;
g_SkipFrame = false;
g_Config.Load();
InitBPMemory();
InitXFMemory();
CommandProcessor::Init();
PixelEngine::Init();
OpcodeDecoder::Init();
Clipper::Init();
Rasterizer::Init();
HwRasterizer::Init();
Renderer::Init(_pVideoInitialize);
}
void DoState(unsigned char **ptr, int mode)
{
}
void Shutdown(void)
{
}
// This is called after Video_Initialize() from the Core
void Video_Prepare(void)
{
Renderer::Prepare();
INFO_LOG(VIDEO, "Video plugin initialized.");
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
}
// Run from the CPU thread (from VideoInterface.cpp)
void Video_EndField()
{
}
u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y)
{
u32 value = 0;
switch (type)
{
case PEEK_Z:
{
value = EfbInterface::GetDepth(x, y);
break;
}
case POKE_Z:
break;
case PEEK_COLOR:
{
u32 color = 0;
EfbInterface::GetColor(x, y, (u8*)&color);
// rgba to argb
value = (color >> 8) | (color & 0xff) << 24;
break;
}
case POKE_COLOR:
break;
}
return value;
}
void Video_Screenshot(const char *_szFilename)
{
}
// -------------------------------
// Enter and exit the video loop
// -------------------------------
void Video_EnterLoop()
{
fifoStateRun = true;
while (fifoStateRun)
{
if (!CommandProcessor::RunBuffer())
Common::SleepCurrentThread(1);
}
}
void Video_ExitLoop()
{
}
void Video_AddMessage(const char* pstr, u32 milliseconds)
{
}
void Video_SetRendering(bool bEnabled)
{
}
void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address)
{
CommandProcessor::Read16(_rReturnValue, _Address);
}
void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address)
{
CommandProcessor::Write16(_Data, _Address);
}
void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address)
{
PixelEngine::Read16(_rReturnValue, _Address);
}
void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address)
{
PixelEngine::Write16(_Data, _Address);
}
void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address)
{
PixelEngine::Write32(_Data, _Address);
}
inline void Video_GatherPipeBursted(void)
{
CommandProcessor::GatherPipeBursted();
}
void Video_WaitForFrameFinish(void)
{
}

View File

@ -0,0 +1,27 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef MAIN_H
#define MAIN_H
#include "PluginSpecs_Video.h"
extern SVideoInitialize g_VideoInitialize;
extern bool g_SkipFrame;
#endif

View File

@ -0,0 +1,18 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "stdafx.h"

View File

@ -0,0 +1,26 @@
// Copyright (C) 2003-2009 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#define _WIN32_WINNT 0x501
#ifndef _WIN32_IE
#define _WIN32_IE 0x0500 // Default value is 0x0400
#endif
#include <tchar.h>
#include <windows.h>