diff --git a/Source/Core/Core/Src/PowerPC/CPUCoreBase.h b/Source/Core/Core/Src/PowerPC/CPUCoreBase.h index efd8a29059..5163d2034b 100644 --- a/Source/Core/Core/Src/PowerPC/CPUCoreBase.h +++ b/Source/Core/Core/Src/PowerPC/CPUCoreBase.h @@ -1,32 +1,32 @@ -// Copyright (C) 2010 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 _CPUCOREBASE_H -#define _CPUCOREBASE_H - -class CPUCoreBase -{ -public: - virtual void Init() = 0; - virtual void Shutdown() = 0; - virtual void ClearCache() = 0; - virtual void Run() = 0; - virtual void SingleStep() = 0; - virtual const char *GetName() = 0; -}; - -#endif +// Copyright (C) 2010 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 _CPUCOREBASE_H +#define _CPUCOREBASE_H + +class CPUCoreBase +{ +public: + virtual void Init() = 0; + virtual void Shutdown() = 0; + virtual void ClearCache() = 0; + virtual void Run() = 0; + virtual void SingleStep() = 0; + virtual const char *GetName() = 0; +}; + +#endif diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index 642978dcf5..2c1f3ce26b 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -1,158 +1,158 @@ - -#include "Common.h" - -#include "Statistics.h" -#include "OpcodeDecoding.h" -#include "IndexGenerator.h" - -#include "VertexManagerBase.h" - -VertexManager *g_vertex_manager; - -u8 *VertexManager::s_pCurBufferPointer; -u8 *VertexManager::s_pBaseBufferPointer; - -u8 *VertexManager::LocalVBuffer; -u16 *VertexManager::TIBuffer; -u16 *VertexManager::LIBuffer; -u16 *VertexManager::PIBuffer; - -bool VertexManager::Flushed; - -VertexManager::VertexManager() -{ - Flushed = false; - - LocalVBuffer = new u8[MAXVBUFFERSIZE]; - s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer; - - TIBuffer = new u16[MAXIBUFFERSIZE]; - LIBuffer = new u16[MAXIBUFFERSIZE]; - PIBuffer = new u16[MAXIBUFFERSIZE]; - - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); -} - -void VertexManager::ResetBuffer() -{ - s_pCurBufferPointer = LocalVBuffer; -} - -VertexManager::~VertexManager() -{ - delete[] LocalVBuffer; - - delete[] TIBuffer; - delete[] LIBuffer; - delete[] PIBuffer; - - // TODO: necessary?? - ResetBuffer(); -} - -void VertexManager::AddIndices(int primitive, int numVertices) -{ - //switch (primitive) - //{ - //case GX_DRAW_QUADS: IndexGenerator::AddQuads(numVertices); break; - //case GX_DRAW_TRIANGLES: IndexGenerator::AddList(numVertices); break; - //case GX_DRAW_TRIANGLE_STRIP: IndexGenerator::AddStrip(numVertices); break; - //case GX_DRAW_TRIANGLE_FAN: IndexGenerator::AddFan(numVertices); break; - //case GX_DRAW_LINES: IndexGenerator::AddLineList(numVertices); break; - //case GX_DRAW_LINE_STRIP: IndexGenerator::AddLineStrip(numVertices); break; - //case GX_DRAW_POINTS: IndexGenerator::AddPoints(numVertices); break; - //} - - static void (*const primitive_table[])(int) = - { - IndexGenerator::AddQuads, - NULL, - IndexGenerator::AddList, - IndexGenerator::AddStrip, - IndexGenerator::AddFan, - IndexGenerator::AddLineList, - IndexGenerator::AddLineStrip, - IndexGenerator::AddPoints, - }; - - primitive_table[primitive](numVertices); -} - -int VertexManager::GetRemainingSize() -{ - return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer); -} - -int VertexManager::GetRemainingVertices(int primitive) -{ - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_TRIANGLES: - case GX_DRAW_TRIANGLE_STRIP: - case GX_DRAW_TRIANGLE_FAN: - return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3; - break; - - case GX_DRAW_LINES: - case GX_DRAW_LINE_STRIP: - return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2; - break; - - case GX_DRAW_POINTS: - return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen()); - break; - - default: - return 0; - break; - } -} - -void VertexManager::AddVertices(int primitive, int numVertices) -{ - if (numVertices <= 0) - return; - - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_TRIANGLES: - case GX_DRAW_TRIANGLE_STRIP: - case GX_DRAW_TRIANGLE_FAN: - if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * numVertices) - Flush(); - break; - - case GX_DRAW_LINES: - case GX_DRAW_LINE_STRIP: - if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * numVertices) - Flush(); - break; - - case GX_DRAW_POINTS: - if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < numVertices) - Flush(); - break; - - default: - return; - break; - } - - if (Flushed) - { - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); - Flushed = false; - } - - ADDSTAT(stats.thisFrame.numPrims, numVertices); - INCSTAT(stats.thisFrame.numPrimitiveJoins); - AddIndices(primitive, numVertices); -} - -// TODO: merge this func, (need to merge TextureCache) -void VertexManager::Flush() -{ - g_vertex_manager->vFlush(); -} + +#include "Common.h" + +#include "Statistics.h" +#include "OpcodeDecoding.h" +#include "IndexGenerator.h" + +#include "VertexManagerBase.h" + +VertexManager *g_vertex_manager; + +u8 *VertexManager::s_pCurBufferPointer; +u8 *VertexManager::s_pBaseBufferPointer; + +u8 *VertexManager::LocalVBuffer; +u16 *VertexManager::TIBuffer; +u16 *VertexManager::LIBuffer; +u16 *VertexManager::PIBuffer; + +bool VertexManager::Flushed; + +VertexManager::VertexManager() +{ + Flushed = false; + + LocalVBuffer = new u8[MAXVBUFFERSIZE]; + s_pCurBufferPointer = s_pBaseBufferPointer = LocalVBuffer; + + TIBuffer = new u16[MAXIBUFFERSIZE]; + LIBuffer = new u16[MAXIBUFFERSIZE]; + PIBuffer = new u16[MAXIBUFFERSIZE]; + + IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); +} + +void VertexManager::ResetBuffer() +{ + s_pCurBufferPointer = LocalVBuffer; +} + +VertexManager::~VertexManager() +{ + delete[] LocalVBuffer; + + delete[] TIBuffer; + delete[] LIBuffer; + delete[] PIBuffer; + + // TODO: necessary?? + ResetBuffer(); +} + +void VertexManager::AddIndices(int primitive, int numVertices) +{ + //switch (primitive) + //{ + //case GX_DRAW_QUADS: IndexGenerator::AddQuads(numVertices); break; + //case GX_DRAW_TRIANGLES: IndexGenerator::AddList(numVertices); break; + //case GX_DRAW_TRIANGLE_STRIP: IndexGenerator::AddStrip(numVertices); break; + //case GX_DRAW_TRIANGLE_FAN: IndexGenerator::AddFan(numVertices); break; + //case GX_DRAW_LINES: IndexGenerator::AddLineList(numVertices); break; + //case GX_DRAW_LINE_STRIP: IndexGenerator::AddLineStrip(numVertices); break; + //case GX_DRAW_POINTS: IndexGenerator::AddPoints(numVertices); break; + //} + + static void (*const primitive_table[])(int) = + { + IndexGenerator::AddQuads, + NULL, + IndexGenerator::AddList, + IndexGenerator::AddStrip, + IndexGenerator::AddFan, + IndexGenerator::AddLineList, + IndexGenerator::AddLineStrip, + IndexGenerator::AddPoints, + }; + + primitive_table[primitive](numVertices); +} + +int VertexManager::GetRemainingSize() +{ + return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer); +} + +int VertexManager::GetRemainingVertices(int primitive) +{ + switch (primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_TRIANGLES: + case GX_DRAW_TRIANGLE_STRIP: + case GX_DRAW_TRIANGLE_FAN: + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3; + break; + + case GX_DRAW_LINES: + case GX_DRAW_LINE_STRIP: + return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2; + break; + + case GX_DRAW_POINTS: + return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen()); + break; + + default: + return 0; + break; + } +} + +void VertexManager::AddVertices(int primitive, int numVertices) +{ + if (numVertices <= 0) + return; + + switch (primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_TRIANGLES: + case GX_DRAW_TRIANGLE_STRIP: + case GX_DRAW_TRIANGLE_FAN: + if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * numVertices) + Flush(); + break; + + case GX_DRAW_LINES: + case GX_DRAW_LINE_STRIP: + if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * numVertices) + Flush(); + break; + + case GX_DRAW_POINTS: + if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < numVertices) + Flush(); + break; + + default: + return; + break; + } + + if (Flushed) + { + IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); + Flushed = false; + } + + ADDSTAT(stats.thisFrame.numPrims, numVertices); + INCSTAT(stats.thisFrame.numPrimitiveJoins); + AddIndices(primitive, numVertices); +} + +// TODO: merge this func, (need to merge TextureCache) +void VertexManager::Flush() +{ + g_vertex_manager->vFlush(); +} diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.h b/Source/Core/VideoCommon/Src/VertexManagerBase.h index c73730d705..e1982e5d06 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.h +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.h @@ -1,57 +1,57 @@ - -#ifndef _VERTEXMANAGERBASE_H -#define _VERTEXMANAGERBASE_H - -class VertexManager -{ -public: - - enum - { - // values from OGL plugin - //MAXVBUFFERSIZE = 0x1FFFF, - //MAXIBUFFERSIZE = 0xFFFF, - - // values from DX9 plugin - //MAXVBUFFERSIZE = 0x50000, - //MAXIBUFFERSIZE = 0xFFFF, - - // values from DX11 plugin - MAXVBUFFERSIZE = 0x50000, - MAXIBUFFERSIZE = 0x10000, - }; - - VertexManager(); - virtual ~VertexManager(); // needs to be virtual for DX11's dtor - - static void AddVertices(int _primitive, int _numVertices); - - // TODO: protected? - static u8 *s_pCurBufferPointer; - static u8 *s_pBaseBufferPointer; - - static int GetRemainingSize(); - static int GetRemainingVertices(int primitive); - - static void Flush(); - -protected: - // TODO: make private after Flush() is merged - static void ResetBuffer(); - - static u8 *LocalVBuffer; - static u16 *TIBuffer; - static u16 *LIBuffer; - static u16 *PIBuffer; - - static bool Flushed; - -private: - static void AddIndices(int primitive, int numVertices); - // temporary - virtual void vFlush() = 0; -}; - -extern VertexManager *g_vertex_manager; - -#endif + +#ifndef _VERTEXMANAGERBASE_H +#define _VERTEXMANAGERBASE_H + +class VertexManager +{ +public: + + enum + { + // values from OGL plugin + //MAXVBUFFERSIZE = 0x1FFFF, + //MAXIBUFFERSIZE = 0xFFFF, + + // values from DX9 plugin + //MAXVBUFFERSIZE = 0x50000, + //MAXIBUFFERSIZE = 0xFFFF, + + // values from DX11 plugin + MAXVBUFFERSIZE = 0x50000, + MAXIBUFFERSIZE = 0x10000, + }; + + VertexManager(); + virtual ~VertexManager(); // needs to be virtual for DX11's dtor + + static void AddVertices(int _primitive, int _numVertices); + + // TODO: protected? + static u8 *s_pCurBufferPointer; + static u8 *s_pBaseBufferPointer; + + static int GetRemainingSize(); + static int GetRemainingVertices(int primitive); + + static void Flush(); + +protected: + // TODO: make private after Flush() is merged + static void ResetBuffer(); + + static u8 *LocalVBuffer; + static u16 *TIBuffer; + static u16 *LIBuffer; + static u16 *PIBuffer; + + static bool Flushed; + +private: + static void AddIndices(int primitive, int numVertices); + // temporary + virtual void vFlush() = 0; +}; + +extern VertexManager *g_vertex_manager; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Plugin_VideoMerge.vcproj b/Source/Plugins/Plugin_VideoMerge/Plugin_VideoMerge.vcproj index ea965c71ce..96b9d3dd6f 100644 --- a/Source/Plugins/Plugin_VideoMerge/Plugin_VideoMerge.vcproj +++ b/Source/Plugins/Plugin_VideoMerge/Plugin_VideoMerge.vcproj @@ -1,808 +1,808 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Plugins/Plugin_VideoMerge/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoMerge/Src/BPFunctions.cpp index 1c16a8d285..9092ccfba8 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/BPFunctions.cpp @@ -1,144 +1,144 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "Common.h" - -// VideoCommon -#include "VideoConfig.h" -#include "BPFunctions.h" -#include "Renderer.h" -#include "VertexShaderManager.h" -#include "VertexManager.h" - -#include "Main.h" - -namespace BPFunctions -{ - -void FlushPipeline() -{ - g_vertex_manager->Flush(); -} - -void SetGenerationMode(const BPCmd &bp) -{ - g_renderer->SetGenerationMode(); -} - -void SetScissor(const BPCmd &bp) -{ - g_renderer->SetScissorRect(); -} - -void SetLineWidth(const BPCmd &bp) -{ - g_renderer->SetLineWidth(); -} - -void SetDepthMode(const BPCmd &bp) -{ - g_renderer->SetDepthMode(); -} - -void SetBlendMode(const BPCmd &bp) -{ - g_renderer->SetBlendMode(false); -} - -void SetDitherMode(const BPCmd &bp) -{ - g_renderer->SetDitherMode(); -} - -void SetLogicOpMode(const BPCmd &bp) -{ - g_renderer->SetLogicOpMode(); -} - -void SetColorMask(const BPCmd &bp) -{ - g_renderer->SetColorMask(); -} - -void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const int &scaleByHalf) -{ - if (!g_ActiveConfig.bEFBCopyDisable) - { -// if (g_ActiveConfig.bCopyEFBToTexture) -// { - g_texture_cache->CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, !!scaleByHalf, rc); -// } -// else -// { -// PanicAlert("TODO: Implement EFB copying to RAM %s %d\n", __FILE__, __LINE__); -// } - } -} - -void ClearScreen(const BPCmd &bp, const EFBRectangle &rc) -{ - bool colorEnable = bpmem.blendmode.colorupdate; - bool alphaEnable = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24 && bpmem.blendmode.alphaupdate); - bool zEnable = bpmem.zmode.updateenable; - - if (colorEnable || alphaEnable || zEnable) - { - u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; - u32 z = bpmem.clearZValue; - - g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); - } -} - -void RestoreRenderState(const BPCmd &bp) -{ - g_renderer->RestoreAPIState(); -} - -bool GetConfig(const int &type) -{ - switch (type) - { - case CONFIG_ISWII: - return g_VideoInitialize.bWii; - case CONFIG_DISABLEFOG: - return g_ActiveConfig.bDisableFog; - case CONFIG_SHOWEFBREGIONS: - return false; - default: - PanicAlert("GetConfig Error: Unknown Config Type!"); - return false; - } -} - -u8 *GetPointer(const u32 &address) -{ - return g_VideoInitialize.pGetMemoryPointer(address); -} - -void SetTextureMode(const BPCmd &bp) -{ - g_renderer->SetSamplerState(bp.address & 3, (bp.address & 0xE0) == 0xA0); -} - -void SetInterlacingMode(const BPCmd &bp) -{ - // TODO -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "Common.h" + +// VideoCommon +#include "VideoConfig.h" +#include "BPFunctions.h" +#include "Renderer.h" +#include "VertexShaderManager.h" +#include "VertexManager.h" + +#include "Main.h" + +namespace BPFunctions +{ + +void FlushPipeline() +{ + g_vertex_manager->Flush(); +} + +void SetGenerationMode(const BPCmd &bp) +{ + g_renderer->SetGenerationMode(); +} + +void SetScissor(const BPCmd &bp) +{ + g_renderer->SetScissorRect(); +} + +void SetLineWidth(const BPCmd &bp) +{ + g_renderer->SetLineWidth(); +} + +void SetDepthMode(const BPCmd &bp) +{ + g_renderer->SetDepthMode(); +} + +void SetBlendMode(const BPCmd &bp) +{ + g_renderer->SetBlendMode(false); +} + +void SetDitherMode(const BPCmd &bp) +{ + g_renderer->SetDitherMode(); +} + +void SetLogicOpMode(const BPCmd &bp) +{ + g_renderer->SetLogicOpMode(); +} + +void SetColorMask(const BPCmd &bp) +{ + g_renderer->SetColorMask(); +} + +void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const int &scaleByHalf) +{ + if (!g_ActiveConfig.bEFBCopyDisable) + { +// if (g_ActiveConfig.bCopyEFBToTexture) +// { + g_texture_cache->CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, !!scaleByHalf, rc); +// } +// else +// { +// PanicAlert("TODO: Implement EFB copying to RAM %s %d\n", __FILE__, __LINE__); +// } + } +} + +void ClearScreen(const BPCmd &bp, const EFBRectangle &rc) +{ + bool colorEnable = bpmem.blendmode.colorupdate; + bool alphaEnable = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24 && bpmem.blendmode.alphaupdate); + bool zEnable = bpmem.zmode.updateenable; + + if (colorEnable || alphaEnable || zEnable) + { + u32 color = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; + u32 z = bpmem.clearZValue; + + g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); + } +} + +void RestoreRenderState(const BPCmd &bp) +{ + g_renderer->RestoreAPIState(); +} + +bool GetConfig(const int &type) +{ + switch (type) + { + case CONFIG_ISWII: + return g_VideoInitialize.bWii; + case CONFIG_DISABLEFOG: + return g_ActiveConfig.bDisableFog; + case CONFIG_SHOWEFBREGIONS: + return false; + default: + PanicAlert("GetConfig Error: Unknown Config Type!"); + return false; + } +} + +u8 *GetPointer(const u32 &address) +{ + return g_VideoInitialize.pGetMemoryPointer(address); +} + +void SetTextureMode(const BPCmd &bp) +{ + g_renderer->SetSamplerState(bp.address & 3, (bp.address & 0xE0) == 0xA0); +} + +void SetInterlacingMode(const BPCmd &bp) +{ + // TODO +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.cpp index 4d83237ec4..6d56534a0b 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.cpp @@ -1,338 +1,338 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "StringUtil.h" - -// VideoCommon -#include "VideoConfig.h" -#include "XFStructs.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DTexture.h" -#include "DX11_D3DShader.h" -#include "DX11_Render.h" - -#include - -#pragma comment(lib, "dxguid.lib") -#pragma comment(lib, "d3d11.lib") -#pragma comment(lib, "dxgi.lib") - -namespace DX11 -{ - -HINSTANCE hD3DXDll = NULL; -D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL; -D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL; -D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL; -D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL; - -namespace D3D -{ - -ID3D11Device* device = NULL; -ID3D11DeviceContext* context = NULL; -IDXGISwapChain* swapchain = NULL; -D3D_FEATURE_LEVEL featlevel; -D3DTexture2D* backbuf = NULL; -HWND hWnd; - -bool bgra_textures_supported; - -#define NUM_SUPPORTED_FEATURE_LEVELS 3 -const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0 -}; - -unsigned int xres, yres; - -bool bFrameInProgress = false; - -HRESULT Create(HWND wnd) -{ - hWnd = wnd; - HRESULT hr; - - RECT client; - GetClientRect(hWnd, &client); - xres = client.right - client.left; - yres = client.bottom - client.top; - - // try to load D3DX11 first to check whether we have proper runtime support - // try to use the dll the plugin was compiled against first - don't bother about debug runtimes - hD3DXDll = LoadLibraryA(StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str()); - if (!hD3DXDll) - { - // if that fails, use the dll which should be available in every SDK which officially supports DX11. - hD3DXDll = LoadLibraryA("d3dx11_42.dll"); - if (!hD3DXDll) - { - MessageBoxA(NULL, "Failed to load d3dx11_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR); - return E_FAIL; - } - else - { - NOTICE_LOG(VIDEO, "Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first."); - } - } - else - { - NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str()); - } - - PD3DX11CompileFromMemory = (D3DX11COMPILEFROMMEMORYTYPE)GetProcAddress(hD3DXDll, "D3DX11CompileFromMemory"); - if (PD3DX11CompileFromMemory == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11CompileFromMemory!", "Critical error", MB_OK | MB_ICONERROR); - - PD3DX11FilterTexture = (D3DX11FILTERTEXTURETYPE)GetProcAddress(hD3DXDll, "D3DX11FilterTexture"); - if (PD3DX11FilterTexture == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11FilterTexture!", "Critical error", MB_OK | MB_ICONERROR); - - PD3DX11SaveTextureToFileA = (D3DX11SAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileA"); - if (PD3DX11SaveTextureToFileA == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR); - - PD3DX11SaveTextureToFileW = (D3DX11SAVETEXTURETOFILEWTYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileW"); - if (PD3DX11SaveTextureToFileW == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileW!", "Critical error", MB_OK | MB_ICONERROR); - - // D3DX11 is fine, initialize D3D11 - IDXGIFactory* factory; - IDXGIAdapter* adapter; - IDXGIOutput* output; - hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - - hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); - if (FAILED(hr)) - { - // try using the first one - hr = factory->EnumAdapters(0, &adapter); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - } - - // TODO: Make this configurable - hr = adapter->EnumOutputs(0, &output); - if (FAILED(hr)) - { - // try using the first one - hr = adapter->EnumOutputs(0, &output); - if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate outputs"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - } - - // this will need to be changed once multisampling gets implemented - DXGI_SWAP_CHAIN_DESC swap_chain_desc; - memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); - swap_chain_desc.BufferCount = 1; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = wnd; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Windowed = TRUE; - - DXGI_MODE_DESC mode_desc; - memset(&mode_desc, 0, sizeof(mode_desc)); - mode_desc.Width = xres; - mode_desc.Height = yres; - mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, NULL); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - - // forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported! - swap_chain_desc.BufferDesc.Width = xres; - swap_chain_desc.BufferDesc.Height = yres; - -#if defined(_DEBUG) || defined(DEBUGFAST) - D3D11_CREATE_DEVICE_FLAG device_flags = (D3D11_CREATE_DEVICE_FLAG)(D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_SINGLETHREADED); -#else - D3D11_CREATE_DEVICE_FLAG device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED; -#endif - hr = D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, device_flags, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, - &featlevel, &context); - if (FAILED(hr) || !device || !context || !swapchain) - { - MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return E_FAIL; - } - SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); - SAFE_RELEASE(factory); - SAFE_RELEASE(output); - SAFE_RELEASE(adapter); - - ID3D11Texture2D* buf; - hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); - if (FAILED(hr)) - { - MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return E_FAIL; - } - backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - CHECK(backbuf!=NULL, "Create back buffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); - - context->OMSetRenderTargets(1, &backbuf->GetRTV(), NULL); - - // BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware - UINT format_support; - device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); - bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; - - gfxstate = new EmuGfxState; - stateman = new StateManager; - return S_OK; -} - -void Close() -{ - // unload D3DX11 - FreeLibrary(hD3DXDll); - PD3DX11FilterTexture = NULL; - PD3DX11SaveTextureToFileA = NULL; - PD3DX11SaveTextureToFileW = NULL; - - // release all bound resources - context->ClearState(); - SAFE_RELEASE(backbuf); - SAFE_RELEASE(swapchain); - SAFE_DELETE(gfxstate); - SAFE_DELETE(stateman); - context->Flush(); // immediately destroy device objects - - SAFE_RELEASE(context); - ULONG references = device->Release(); - if (references) - { - ERROR_LOG(VIDEO, "Unreleased references: %i.", references); - } - else - { - NOTICE_LOG(VIDEO, "Successfully released all device references!"); - } - device = NULL; -} - -/* just returning the 4_0 ones here */ -const char* VertexShaderVersionString() { return "vs_4_0"; } -const char* PixelShaderVersionString() { return "ps_4_0"; } - -D3DTexture2D* &GetBackBuffer() { return backbuf; } -unsigned int GetBackBufferWidth() { return xres; } -unsigned int GetBackBufferHeight() { return yres; } - -bool BGRATexturesSupported() { return bgra_textures_supported; } - -// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11 -unsigned int GetMaxTextureSize() -{ - switch (featlevel) - { - case D3D_FEATURE_LEVEL_11_0: - return 16384; - break; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return 8192; - break; - - case D3D_FEATURE_LEVEL_9_3: - return 4096; - break; - - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return 2048; - break; - - default: - return 0; - break; - } -} - -void Reset() -{ - // release all back buffer references - SAFE_RELEASE(backbuf); - - // resize swapchain buffers - RECT client; - GetClientRect(hWnd, &client); - xres = client.right - client.left; - yres = client.bottom - client.top; - D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); - - // recreate back buffer texture - ID3D11Texture2D* buf; - HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); - if (FAILED(hr)) - { - MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(swapchain); - return; - } - backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - CHECK(backbuf!=NULL, "Create back buffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); - SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); -} - -bool BeginFrame() -{ - if (bFrameInProgress) - { - PanicAlert("BeginFrame called although a frame is already in progress"); - return false; - } - bFrameInProgress = true; - return (device != NULL); -} - -void EndFrame() -{ - if (!bFrameInProgress) - { - PanicAlert("EndFrame called although no frame is in progress"); - return; - } - bFrameInProgress = false; -} - -void Present() -{ - // TODO: Is 1 the correct value for vsyncing? - swapchain->Present((UINT)g_ActiveConfig.bVSync, 0); -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "StringUtil.h" + +// VideoCommon +#include "VideoConfig.h" +#include "XFStructs.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DTexture.h" +#include "DX11_D3DShader.h" +#include "DX11_Render.h" + +#include + +#pragma comment(lib, "dxguid.lib") +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "dxgi.lib") + +namespace DX11 +{ + +HINSTANCE hD3DXDll = NULL; +D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL; +D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL; +D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL; +D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL; + +namespace D3D +{ + +ID3D11Device* device = NULL; +ID3D11DeviceContext* context = NULL; +IDXGISwapChain* swapchain = NULL; +D3D_FEATURE_LEVEL featlevel; +D3DTexture2D* backbuf = NULL; +HWND hWnd; + +bool bgra_textures_supported; + +#define NUM_SUPPORTED_FEATURE_LEVELS 3 +const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0 +}; + +unsigned int xres, yres; + +bool bFrameInProgress = false; + +HRESULT Create(HWND wnd) +{ + hWnd = wnd; + HRESULT hr; + + RECT client; + GetClientRect(hWnd, &client); + xres = client.right - client.left; + yres = client.bottom - client.top; + + // try to load D3DX11 first to check whether we have proper runtime support + // try to use the dll the plugin was compiled against first - don't bother about debug runtimes + hD3DXDll = LoadLibraryA(StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str()); + if (!hD3DXDll) + { + // if that fails, use the dll which should be available in every SDK which officially supports DX11. + hD3DXDll = LoadLibraryA("d3dx11_42.dll"); + if (!hD3DXDll) + { + MessageBoxA(NULL, "Failed to load d3dx11_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR); + return E_FAIL; + } + else + { + NOTICE_LOG(VIDEO, "Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first."); + } + } + else + { + NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str()); + } + + PD3DX11CompileFromMemory = (D3DX11COMPILEFROMMEMORYTYPE)GetProcAddress(hD3DXDll, "D3DX11CompileFromMemory"); + if (PD3DX11CompileFromMemory == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11CompileFromMemory!", "Critical error", MB_OK | MB_ICONERROR); + + PD3DX11FilterTexture = (D3DX11FILTERTEXTURETYPE)GetProcAddress(hD3DXDll, "D3DX11FilterTexture"); + if (PD3DX11FilterTexture == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11FilterTexture!", "Critical error", MB_OK | MB_ICONERROR); + + PD3DX11SaveTextureToFileA = (D3DX11SAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileA"); + if (PD3DX11SaveTextureToFileA == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR); + + PD3DX11SaveTextureToFileW = (D3DX11SAVETEXTURETOFILEWTYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileW"); + if (PD3DX11SaveTextureToFileW == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileW!", "Critical error", MB_OK | MB_ICONERROR); + + // D3DX11 is fine, initialize D3D11 + IDXGIFactory* factory; + IDXGIAdapter* adapter; + IDXGIOutput* output; + hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); + if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + + hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); + if (FAILED(hr)) + { + // try using the first one + hr = factory->EnumAdapters(0, &adapter); + if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + } + + // TODO: Make this configurable + hr = adapter->EnumOutputs(0, &output); + if (FAILED(hr)) + { + // try using the first one + hr = adapter->EnumOutputs(0, &output); + if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate outputs"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + } + + // this will need to be changed once multisampling gets implemented + DXGI_SWAP_CHAIN_DESC swap_chain_desc; + memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); + swap_chain_desc.BufferCount = 1; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.OutputWindow = wnd; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Windowed = TRUE; + + DXGI_MODE_DESC mode_desc; + memset(&mode_desc, 0, sizeof(mode_desc)); + mode_desc.Width = xres; + mode_desc.Height = yres; + mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, NULL); + if (FAILED(hr)) + MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + + // forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported! + swap_chain_desc.BufferDesc.Width = xres; + swap_chain_desc.BufferDesc.Height = yres; + +#if defined(_DEBUG) || defined(DEBUGFAST) + D3D11_CREATE_DEVICE_FLAG device_flags = (D3D11_CREATE_DEVICE_FLAG)(D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_SINGLETHREADED); +#else + D3D11_CREATE_DEVICE_FLAG device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED; +#endif + hr = D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, device_flags, + supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, + D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, + &featlevel, &context); + if (FAILED(hr) || !device || !context || !swapchain) + { + MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return E_FAIL; + } + SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); + SAFE_RELEASE(factory); + SAFE_RELEASE(output); + SAFE_RELEASE(adapter); + + ID3D11Texture2D* buf; + hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); + if (FAILED(hr)) + { + MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return E_FAIL; + } + backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + CHECK(backbuf!=NULL, "Create back buffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); + + context->OMSetRenderTargets(1, &backbuf->GetRTV(), NULL); + + // BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware + UINT format_support; + device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); + bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; + + gfxstate = new EmuGfxState; + stateman = new StateManager; + return S_OK; +} + +void Close() +{ + // unload D3DX11 + FreeLibrary(hD3DXDll); + PD3DX11FilterTexture = NULL; + PD3DX11SaveTextureToFileA = NULL; + PD3DX11SaveTextureToFileW = NULL; + + // release all bound resources + context->ClearState(); + SAFE_RELEASE(backbuf); + SAFE_RELEASE(swapchain); + SAFE_DELETE(gfxstate); + SAFE_DELETE(stateman); + context->Flush(); // immediately destroy device objects + + SAFE_RELEASE(context); + ULONG references = device->Release(); + if (references) + { + ERROR_LOG(VIDEO, "Unreleased references: %i.", references); + } + else + { + NOTICE_LOG(VIDEO, "Successfully released all device references!"); + } + device = NULL; +} + +/* just returning the 4_0 ones here */ +const char* VertexShaderVersionString() { return "vs_4_0"; } +const char* PixelShaderVersionString() { return "ps_4_0"; } + +D3DTexture2D* &GetBackBuffer() { return backbuf; } +unsigned int GetBackBufferWidth() { return xres; } +unsigned int GetBackBufferHeight() { return yres; } + +bool BGRATexturesSupported() { return bgra_textures_supported; } + +// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11 +unsigned int GetMaxTextureSize() +{ + switch (featlevel) + { + case D3D_FEATURE_LEVEL_11_0: + return 16384; + break; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 8192; + break; + + case D3D_FEATURE_LEVEL_9_3: + return 4096; + break; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 2048; + break; + + default: + return 0; + break; + } +} + +void Reset() +{ + // release all back buffer references + SAFE_RELEASE(backbuf); + + // resize swapchain buffers + RECT client; + GetClientRect(hWnd, &client); + xres = client.right - client.left; + yres = client.bottom - client.top; + D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); + + // recreate back buffer texture + ID3D11Texture2D* buf; + HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf); + if (FAILED(hr)) + { + MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 plugin"), MB_OK | MB_ICONERROR); + SAFE_RELEASE(device); + SAFE_RELEASE(context); + SAFE_RELEASE(swapchain); + return; + } + backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + CHECK(backbuf!=NULL, "Create back buffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture"); + SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view"); +} + +bool BeginFrame() +{ + if (bFrameInProgress) + { + PanicAlert("BeginFrame called although a frame is already in progress"); + return false; + } + bFrameInProgress = true; + return (device != NULL); +} + +void EndFrame() +{ + if (!bFrameInProgress) + { + PanicAlert("EndFrame called although no frame is in progress"); + return; + } + bFrameInProgress = false; +} + +void Present() +{ + // TODO: Is 1 the correct value for vsyncing? + swapchain->Present((UINT)g_ActiveConfig.bVSync, 0); +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.h index 8e86a55b8e..63587f89ac 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBase.h @@ -1,96 +1,96 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -// Common -#include "Common.h" - -// DX11 -#include -#include "DX11_GfxState.h" -#include "DX11_D3DBlob.h" - -namespace DX11 -{ - -#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; } -#define SAFE_DELETE(x) { delete (x); (x) = NULL; } -#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = NULL; } -#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } - -class D3DTexture2D; -namespace D3D -{ - -HRESULT Create(HWND wnd); -void Close(); - -extern ID3D11Device* device; -extern ID3D11DeviceContext* context; -extern IDXGISwapChain* swapchain; -extern bool bFrameInProgress; - -void Reset(); -bool BeginFrame(); -void EndFrame(); -void Present(); - -unsigned int GetBackBufferWidth(); -unsigned int GetBackBufferHeight(); -D3DTexture2D* &GetBackBuffer(); -const char* PixelShaderVersionString(); -const char* VertexShaderVersionString(); -bool BGRATexturesSupported(); - -unsigned int GetMaxTextureSize(); - -// Ihis function will assign a name to the given resource. -// The DirectX debug layer will make it easier to identify resources that way, -// e.g. when listing up all resources who have unreleased references. -inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name) -{ -#if defined(_DEBUG) || defined(DEBUGFAST) - resource->SetPrivateData( WKPDID_D3DDebugObjectName, (UINT)strlen(name), name); -#endif -} - -} // namespace - - -// Used to not require the SDK and runtime versions to match: -// Linking with d3dx11.lib makes the most recent d3dx11_xx.dll of the -// compiler's SDK a requirement, but this plugin works with DX11 runtimes -// back to August 2009 even if the plugin was built with June 2010. -// Add any d3dx11 functions which you want to use here and load them in Create() -typedef HRESULT (WINAPI* D3DX11COMPILEFROMMEMORYTYPE)(LPCSTR, SIZE_T, LPCSTR, const D3D10_SHADER_MACRO*, LPD3D10INCLUDE, LPCSTR, LPCSTR, UINT, UINT, ID3DX11ThreadPump*, ID3D10Blob**, ID3D10Blob**, HRESULT*); -typedef HRESULT (WINAPI* D3DX11FILTERTEXTURETYPE)(ID3D11DeviceContext*, ID3D11Resource*, UINT, UINT); -typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEATYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCSTR); -typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEWTYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCWSTR); - -extern D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory; -extern D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture; -extern D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA; -extern D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW; - -#ifdef UNICODE -#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileW -#else -#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileA -#endif - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// Common +#include "Common.h" + +// DX11 +#include +#include "DX11_GfxState.h" +#include "DX11_D3DBlob.h" + +namespace DX11 +{ + +#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; } +#define SAFE_DELETE(x) { delete (x); (x) = NULL; } +#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = NULL; } +#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } + +class D3DTexture2D; +namespace D3D +{ + +HRESULT Create(HWND wnd); +void Close(); + +extern ID3D11Device* device; +extern ID3D11DeviceContext* context; +extern IDXGISwapChain* swapchain; +extern bool bFrameInProgress; + +void Reset(); +bool BeginFrame(); +void EndFrame(); +void Present(); + +unsigned int GetBackBufferWidth(); +unsigned int GetBackBufferHeight(); +D3DTexture2D* &GetBackBuffer(); +const char* PixelShaderVersionString(); +const char* VertexShaderVersionString(); +bool BGRATexturesSupported(); + +unsigned int GetMaxTextureSize(); + +// Ihis function will assign a name to the given resource. +// The DirectX debug layer will make it easier to identify resources that way, +// e.g. when listing up all resources who have unreleased references. +inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name) +{ +#if defined(_DEBUG) || defined(DEBUGFAST) + resource->SetPrivateData( WKPDID_D3DDebugObjectName, (UINT)strlen(name), name); +#endif +} + +} // namespace + + +// Used to not require the SDK and runtime versions to match: +// Linking with d3dx11.lib makes the most recent d3dx11_xx.dll of the +// compiler's SDK a requirement, but this plugin works with DX11 runtimes +// back to August 2009 even if the plugin was built with June 2010. +// Add any d3dx11 functions which you want to use here and load them in Create() +typedef HRESULT (WINAPI* D3DX11COMPILEFROMMEMORYTYPE)(LPCSTR, SIZE_T, LPCSTR, const D3D10_SHADER_MACRO*, LPD3D10INCLUDE, LPCSTR, LPCSTR, UINT, UINT, ID3DX11ThreadPump*, ID3D10Blob**, ID3D10Blob**, HRESULT*); +typedef HRESULT (WINAPI* D3DX11FILTERTEXTURETYPE)(ID3D11DeviceContext*, ID3D11Resource*, UINT, UINT); +typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEATYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCSTR); +typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEWTYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCWSTR); + +extern D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory; +extern D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture; +extern D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA; +extern D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW; + +#ifdef UNICODE +#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileW +#else +#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileA +#endif + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.cpp index 553bb76435..2709248063 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.cpp @@ -1,68 +1,68 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DX11_D3DBlob.h" - -namespace DX11 -{ - -D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(NULL) -{ - data = new u8[blob_size]; - if (init_data) memcpy(data, init_data, size); -} - -D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1) -{ - blob = d3dblob; - data = (u8*)blob->GetBufferPointer(); - size = blob->GetBufferSize(); - d3dblob->AddRef(); -} - -D3DBlob::~D3DBlob() -{ - if (blob) blob->Release(); - else delete[] data; -} - -void D3DBlob::AddRef() -{ - ++ref; -} - -unsigned int D3DBlob::Release() -{ - if (--ref == 0) - { - delete this; - return 0; - } - return ref; -} - -unsigned int D3DBlob::Size() -{ - return size; -} - -u8* D3DBlob::Data() -{ - return data; -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DX11_D3DBlob.h" + +namespace DX11 +{ + +D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(NULL) +{ + data = new u8[blob_size]; + if (init_data) memcpy(data, init_data, size); +} + +D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1) +{ + blob = d3dblob; + data = (u8*)blob->GetBufferPointer(); + size = blob->GetBufferSize(); + d3dblob->AddRef(); +} + +D3DBlob::~D3DBlob() +{ + if (blob) blob->Release(); + else delete[] data; +} + +void D3DBlob::AddRef() +{ + ++ref; +} + +unsigned int D3DBlob::Release() +{ + if (--ref == 0) + { + delete this; + return 0; + } + return ref; +} + +unsigned int D3DBlob::Size() +{ + return size; +} + +u8* D3DBlob::Data() +{ + return data; +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.h index 01bbc38f17..1a559db83e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DBlob.h @@ -1,52 +1,52 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "Common.h" -#include - -namespace DX11 -{ - -// use this class instead ID3D10Blob or ID3D11Blob whenever possible -class D3DBlob -{ -public: - // memory will be copied into an own buffer - D3DBlob(unsigned int blob_size, const u8* init_data = NULL); - - // d3dblob will be AddRef'd - D3DBlob(ID3D10Blob* d3dblob); - - void AddRef(); - unsigned int Release(); - - unsigned int Size(); - u8* Data(); - -private: - ~D3DBlob(); - - unsigned int ref; - unsigned int size; - - u8* data; - ID3D10Blob* blob; -}; - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "Common.h" +#include + +namespace DX11 +{ + +// use this class instead ID3D10Blob or ID3D11Blob whenever possible +class D3DBlob +{ +public: + // memory will be copied into an own buffer + D3DBlob(unsigned int blob_size, const u8* init_data = NULL); + + // d3dblob will be AddRef'd + D3DBlob(ID3D10Blob* d3dblob); + + void AddRef(); + unsigned int Release(); + + unsigned int Size(); + u8* Data(); + +private: + ~D3DBlob(); + + unsigned int ref; + unsigned int size; + + u8* data; + ID3D10Blob* blob; +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.cpp index 9523ed72a6..c8ecf99d11 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.cpp @@ -1,150 +1,150 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include -#include - -#include "VideoConfig.h" -#include "DX11_D3DShader.h" - -namespace DX11 -{ - -namespace D3D -{ - -// bytecode->shader -ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len) -{ - ID3D11VertexShader* v_shader; - HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader); - if (FAILED(hr)) - { - PanicAlert("CreateVertexShaderFromByteCode failed from %p (size %d) at %s %d\n", bytecode, len, __FILE__, __LINE__); - v_shader = NULL; - } - return v_shader; -} - -// code->bytecode -bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob) -{ - ID3D10Blob* shaderBuffer = NULL; - ID3D10Blob* errorBuffer = NULL; - -#if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS; -#else - UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION; -#endif - HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::VertexShaderVersionString(), - flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL); - - if (FAILED(hr) || errorBuffer) - { - std::string msg = (char*)errorBuffer->GetBufferPointer(); - msg += "\n\n"; - msg += code; - MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR); - - *blob = NULL; - errorBuffer->Release(); - } - else - { - *blob = new D3DBlob(shaderBuffer); - shaderBuffer->Release(); - } - return SUCCEEDED(hr); -} - -// bytecode->shader -ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len) -{ - ID3D11PixelShader* p_shader; - HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, NULL, &p_shader); - if (FAILED(hr)) - { - PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__); - p_shader = NULL; - } - return p_shader; -} - -// code->bytecode -bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob) -{ - ID3D10Blob* shaderBuffer = NULL; - ID3D10Blob* errorBuffer = NULL; - -#if defined(_DEBUG) || defined(DEBUGFAST) - UINT flags = D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS; -#else - UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3; -#endif - HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::PixelShaderVersionString(), - flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL); - - if (FAILED(hr) || errorBuffer) - { - std::string msg = (char*)errorBuffer->GetBufferPointer(); - msg += "\n\n"; - msg += code; - MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR); - - *blob = NULL; - errorBuffer->Release(); - } - else - { - *blob = new D3DBlob(shaderBuffer); - shaderBuffer->Release(); - } - return SUCCEEDED(hr); -} - -ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len) -{ - D3DBlob* blob = NULL; - if (CompileVertexShader(code, len, &blob)) - { - ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob); - blob->Release(); - return v_shader; - } - PanicAlert("Failed to compile and create vertex shader from %p (size %d) at %s %d\n", code, len, __FILE__, __LINE__); - return NULL; -} - -ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len) -{ - D3DBlob* blob = NULL; - CompilePixelShader(code, len, &blob); - if (blob) - { - ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob); - blob->Release(); - return p_shader; - } - PanicAlert("Failed to compile and create pixel shader, %s %d\n", __FILE__, __LINE__); - return NULL; -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include +#include + +#include "VideoConfig.h" +#include "DX11_D3DShader.h" + +namespace DX11 +{ + +namespace D3D +{ + +// bytecode->shader +ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len) +{ + ID3D11VertexShader* v_shader; + HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader); + if (FAILED(hr)) + { + PanicAlert("CreateVertexShaderFromByteCode failed from %p (size %d) at %s %d\n", bytecode, len, __FILE__, __LINE__); + v_shader = NULL; + } + return v_shader; +} + +// code->bytecode +bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob) +{ + ID3D10Blob* shaderBuffer = NULL; + ID3D10Blob* errorBuffer = NULL; + +#if defined(_DEBUG) || defined(DEBUGFAST) + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS; +#else + UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION; +#endif + HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::VertexShaderVersionString(), + flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL); + + if (FAILED(hr) || errorBuffer) + { + std::string msg = (char*)errorBuffer->GetBufferPointer(); + msg += "\n\n"; + msg += code; + MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR); + + *blob = NULL; + errorBuffer->Release(); + } + else + { + *blob = new D3DBlob(shaderBuffer); + shaderBuffer->Release(); + } + return SUCCEEDED(hr); +} + +// bytecode->shader +ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len) +{ + ID3D11PixelShader* p_shader; + HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, NULL, &p_shader); + if (FAILED(hr)) + { + PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__); + p_shader = NULL; + } + return p_shader; +} + +// code->bytecode +bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob) +{ + ID3D10Blob* shaderBuffer = NULL; + ID3D10Blob* errorBuffer = NULL; + +#if defined(_DEBUG) || defined(DEBUGFAST) + UINT flags = D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS; +#else + UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3; +#endif + HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::PixelShaderVersionString(), + flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL); + + if (FAILED(hr) || errorBuffer) + { + std::string msg = (char*)errorBuffer->GetBufferPointer(); + msg += "\n\n"; + msg += code; + MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR); + + *blob = NULL; + errorBuffer->Release(); + } + else + { + *blob = new D3DBlob(shaderBuffer); + shaderBuffer->Release(); + } + return SUCCEEDED(hr); +} + +ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len) +{ + D3DBlob* blob = NULL; + if (CompileVertexShader(code, len, &blob)) + { + ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob); + blob->Release(); + return v_shader; + } + PanicAlert("Failed to compile and create vertex shader from %p (size %d) at %s %d\n", code, len, __FILE__, __LINE__); + return NULL; +} + +ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len) +{ + D3DBlob* blob = NULL; + CompilePixelShader(code, len, &blob); + if (blob) + { + ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob); + blob->Release(); + return p_shader; + } + PanicAlert("Failed to compile and create pixel shader, %s %d\n", __FILE__, __LINE__); + return NULL; +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.h index ee34c3a4a0..50b10126fd 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DShader.h @@ -1,44 +1,44 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "DX11_D3DBase.h" - -namespace DX11 -{ - -namespace D3D -{ - ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len); - ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len); - - // The returned bytecode buffers should be Release()d. - bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob); - bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob); - - // Utility functions - ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len); - ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len); - - inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); } - inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); } - inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) { return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); } - inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "DX11_D3DBase.h" + +namespace DX11 +{ + +namespace D3D +{ + ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len); + ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len); + + // The returned bytecode buffers should be Release()d. + bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob); + bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob); + + // Utility functions + ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len); + ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len); + + inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) { return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); } + inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode) { return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); } + inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code) { return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); } + inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.cpp index 8fda3a23ea..408cf4ed2b 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.cpp @@ -1,125 +1,125 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include "DX11_D3DBase.h" -#include "DX11_D3DTexture.h" - -namespace DX11 -{ - -namespace D3D -{ - -void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage) -{ - if (usage == D3D11_USAGE_DYNAMIC) - { - D3D11_MAPPED_SUBRESOURCE map; - HRESULT hr = D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); - CHECK(SUCCEEDED(hr), "ID3D11DeviceContext::Map failed! (%x)", hr); - if (4 * pitch == map.RowPitch) - { - memcpy(map.pData, buffer, map.RowPitch * height); - } - else - { - for (unsigned int y = 0; y < height; ++y) - memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, map.RowPitch); - } - D3D::context->Unmap(pTexture, level); - } - else - { - D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); - D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height); - } -} - -} // namespace - -D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels) -{ - ID3D11Texture2D* pTexture = NULL; - HRESULT hr; - - D3D11_CPU_ACCESS_FLAG cpuflags; - if (usage == D3D11_USAGE_STAGING) - cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ); - else if (usage == D3D11_USAGE_DYNAMIC) - cpuflags = D3D11_CPU_ACCESS_WRITE; - else - cpuflags = (D3D11_CPU_ACCESS_FLAG)0; - - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, 1, levels, bind, usage, cpuflags); - hr = D3D::device->CreateTexture2D(&texdesc, NULL, &pTexture); - if (FAILED(hr)) - { - PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr); - return NULL; - } - - D3DTexture2D* ret = new D3DTexture2D(pTexture, bind); - SAFE_RELEASE(pTexture); - return ret; -} - -void D3DTexture2D::AddRef() -{ - ++ref; -} - -UINT D3DTexture2D::Release() -{ - --ref; - if (ref == 0) - { - delete this; - return 0; - } - return ref; -} - -D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, - DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format) - : ref(1), tex(texptr), srv(NULL), rtv(NULL), dsv(NULL) -{ - D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(D3D11_SRV_DIMENSION_TEXTURE2D, srv_format); - D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D, dsv_format); - D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(D3D11_RTV_DIMENSION_TEXTURE2D, rtv_format); - - if (bind & D3D11_BIND_SHADER_RESOURCE) - D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv); - - if (bind & D3D11_BIND_RENDER_TARGET) - D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv); - - if (bind & D3D11_BIND_DEPTH_STENCIL) - D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv); - - tex->AddRef(); -} - -D3DTexture2D::~D3DTexture2D() -{ - SAFE_RELEASE(srv); - SAFE_RELEASE(rtv); - SAFE_RELEASE(dsv); - SAFE_RELEASE(tex); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include "DX11_D3DBase.h" +#include "DX11_D3DTexture.h" + +namespace DX11 +{ + +namespace D3D +{ + +void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage) +{ + if (usage == D3D11_USAGE_DYNAMIC) + { + D3D11_MAPPED_SUBRESOURCE map; + HRESULT hr = D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); + CHECK(SUCCEEDED(hr), "ID3D11DeviceContext::Map failed! (%x)", hr); + if (4 * pitch == map.RowPitch) + { + memcpy(map.pData, buffer, map.RowPitch * height); + } + else + { + for (unsigned int y = 0; y < height; ++y) + memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, map.RowPitch); + } + D3D::context->Unmap(pTexture, level); + } + else + { + D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); + D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height); + } +} + +} // namespace + +D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels) +{ + ID3D11Texture2D* pTexture = NULL; + HRESULT hr; + + D3D11_CPU_ACCESS_FLAG cpuflags; + if (usage == D3D11_USAGE_STAGING) + cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ); + else if (usage == D3D11_USAGE_DYNAMIC) + cpuflags = D3D11_CPU_ACCESS_WRITE; + else + cpuflags = (D3D11_CPU_ACCESS_FLAG)0; + + D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, 1, levels, bind, usage, cpuflags); + hr = D3D::device->CreateTexture2D(&texdesc, NULL, &pTexture); + if (FAILED(hr)) + { + PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr); + return NULL; + } + + D3DTexture2D* ret = new D3DTexture2D(pTexture, bind); + SAFE_RELEASE(pTexture); + return ret; +} + +void D3DTexture2D::AddRef() +{ + ++ref; +} + +UINT D3DTexture2D::Release() +{ + --ref; + if (ref == 0) + { + delete this; + return 0; + } + return ref; +} + +D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, + DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format) + : ref(1), tex(texptr), srv(NULL), rtv(NULL), dsv(NULL) +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(D3D11_SRV_DIMENSION_TEXTURE2D, srv_format); + D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D, dsv_format); + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(D3D11_RTV_DIMENSION_TEXTURE2D, rtv_format); + + if (bind & D3D11_BIND_SHADER_RESOURCE) + D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv); + + if (bind & D3D11_BIND_RENDER_TARGET) + D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv); + + if (bind & D3D11_BIND_DEPTH_STENCIL) + D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv); + + tex->AddRef(); +} + +D3DTexture2D::~D3DTexture2D() +{ + SAFE_RELEASE(srv); + SAFE_RELEASE(rtv); + SAFE_RELEASE(dsv); + SAFE_RELEASE(tex); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.h index 722848da2a..1b6166d2fb 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DTexture.h @@ -1,60 +1,60 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "DX11_D3DBase.h" - -namespace DX11 -{ - -namespace D3D -{ - void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage); -} - -class D3DTexture2D -{ -public: - // there are two ways to create a D3DTexture2D object: - // either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create - // or let the texture automatically be created by D3DTexture2D::Create - - D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN); - static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1); - - // reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore - void AddRef(); - UINT Release(); - - ID3D11Texture2D* &GetTex() { return tex; } - ID3D11ShaderResourceView* &GetSRV() { return srv; } - ID3D11RenderTargetView* &GetRTV() { return rtv; } - ID3D11DepthStencilView* &GetDSV() { return dsv; } - -private: - ~D3DTexture2D(); - - ID3D11Texture2D* tex; - ID3D11ShaderResourceView* srv; - ID3D11RenderTargetView* rtv; - ID3D11DepthStencilView* dsv; - D3D11_BIND_FLAG bindflags; - UINT ref; -}; - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "DX11_D3DBase.h" + +namespace DX11 +{ + +namespace D3D +{ + void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage); +} + +class D3DTexture2D +{ +public: + // there are two ways to create a D3DTexture2D object: + // either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create + // or let the texture automatically be created by D3DTexture2D::Create + + D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN); + static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1); + + // reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore + void AddRef(); + UINT Release(); + + ID3D11Texture2D* &GetTex() { return tex; } + ID3D11ShaderResourceView* &GetSRV() { return srv; } + ID3D11RenderTargetView* &GetRTV() { return rtv; } + ID3D11DepthStencilView* &GetDSV() { return dsv; } + +private: + ~D3DTexture2D(); + + ID3D11Texture2D* tex; + ID3D11ShaderResourceView* srv; + ID3D11RenderTargetView* rtv; + ID3D11DepthStencilView* dsv; + D3D11_BIND_FLAG bindflags; + UINT ref; +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.cpp index 42987652e5..4a7afd6313 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.cpp @@ -1,651 +1,651 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "Common.h" - -// DX11 -#include "DX11_Render.h" -#include "DX11_D3DBase.h" -#include "DX11_D3DUtil.h" -#include "DX11_D3DTexture.h" -#include "DX11_PixelShaderCache.h" -#include "DX11_VertexShaderCache.h" -#include "DX11_D3DShader.h" - -namespace DX11 -{ - -namespace D3D -{ - -CD3DFont font; - -#define MAX_NUM_VERTICES 300 -struct FONT2DVERTEX { - float x,y,z; - float col[4]; - float tu, tv; -}; - -inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) -{ - FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv; - v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f; - v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f; - v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f; - v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f; - return v; -} - -CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512) -{ - m_pTexture = NULL; - m_pVB = NULL; - m_InputLayout = NULL; - m_pshader = NULL; - m_vshader = NULL; -} - -const char fontpixshader[] = { - "Texture2D tex2D;\n" - "SamplerState linearSampler\n" - "{\n" - " Filter = MIN_MAG_MIP_LINEAR;\n" - " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" - " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "float4 main( PS_INPUT input ) : SV_Target\n" - "{\n" - " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" - "};\n" -}; - -const char fontvertshader[] = { - "struct VS_INPUT\n" - "{\n" - " float4 pos : POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "struct PS_INPUT\n" - "{\n" - " float4 pos : SV_POSITION;\n" - " float4 col : COLOR;\n" - " float2 tex : TEXCOORD;\n" - "};\n" - "PS_INPUT main( VS_INPUT input )\n" - "{\n" - " PS_INPUT output;\n" - " output.pos = input.pos;\n" - " output.col = input.col;\n" - " output.tex = input.tex;\n" - " return output;\n" - "};\n" -}; - -int CD3DFont::Init() -{ - HRESULT hr; - - // prepare to create a bitmap - unsigned int* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(NULL); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0); - SetMapMode(hDC, MM_TEXT); - - // create a GDI font - HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, PROOF_QUALITY, - VARIABLE_PITCH, _T("Tahoma")); - if (NULL == hFont) return E_FAIL; - - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); - - // set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor (hDC, 0); - SetTextAlign(hDC, TA_TOP); - - TEXTMETRICW tm; - GetTextMetricsW(hDC, &tm); - m_LineHeight = tm.tmHeight; - - // loop through all printable characters and output them to the bitmap - // meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if ((int)(x+size.cx+1) > m_dwTexWidth) - { - x = 0; - y += m_LineHeight; - } - - ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); - m_fTexCoords[c][0] = (float) x /m_dwTexWidth; - m_fTexCoords[c][1] = (float) y /m_dwTexHeight; - m_fTexCoords[c][2] = (float)(x+size.cx)/m_dwTexWidth; - m_fTexCoords[c][3] = (float)(y+size.cy)/m_dwTexHeight; - - x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) - } - - // create a new texture for the font - // possible optimization: store the converted data in a buffer and fill the texture on creation. - // That way, we can use a static texture - ID3D11Texture2D* buftex; - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight, - 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, - D3D11_CPU_ACCESS_WRITE); - hr = device->CreateTexture2D(&texdesc, NULL, &buftex); - if (FAILED(hr)) - { - PanicAlert("Failed to create font texture"); - return hr; - } - D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object"); - - // lock the surface and write the alpha values for the set pixels - D3D11_MAPPED_SUBRESOURCE texmap; - hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap); - if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__); - - for (y = 0; y < m_dwTexHeight; y++) - { - u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch); - for (x = 0; x < m_dwTexWidth; x++) - { - const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff); - *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; - } - } - - // clean up - context->Unmap(buftex, 0); - hr = D3D::device->CreateShaderResourceView(buftex, NULL, &m_pTexture); - if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(buftex); - - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); - - SelectObject(hDC, hOldFont); - DeleteObject(hFont); - - // setup device objects for drawing - m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader, sizeof(fontpixshader)); - if (m_pshader == NULL) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object"); - - D3DBlob* vsbytecode; - D3D::CompileVertexShader(fontvertshader, sizeof(fontvertshader), &vsbytecode); - if (vsbytecode == NULL) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); - m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode); - if (m_vshader == NULL) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object"); - - const D3D11_INPUT_ELEMENT_DESC desc[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout); - if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - SAFE_RELEASE(vsbytecode); - - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = TRUE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate); - CHECK(hr==S_OK, "Create font blend state"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object"); - - // this might need to be changed when adding multisampling support - D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false); - hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate); - CHECK(hr==S_OK, "Create font rasterizer state"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object"); - - D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - if (FAILED(hr = device->CreateBuffer(&vbdesc, NULL, &m_pVB))) - { - PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__); - return hr; - } - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object"); - return S_OK; -} - -int CD3DFont::Shutdown() -{ - SAFE_RELEASE(m_pVB); - SAFE_RELEASE(m_pTexture); - SAFE_RELEASE(m_InputLayout); - SAFE_RELEASE(m_pshader); - SAFE_RELEASE(m_vshader); - - SAFE_RELEASE(m_blendstate); - SAFE_RELEASE(m_raststate); - - return S_OK; -} - -int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const char* strText, bool center) -{ - if (!m_pVB) return 0; - - UINT stride = sizeof(FONT2DVERTEX); - UINT bufoffset = 0; - - float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f; - float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f; - float sizeratio = size / (float)m_LineHeight; - - // translate starting positions - float sx = x * scalex - 1.f; - float sy = 1.f - y * scaley; - char c; - - // fill vertex buffer - FONT2DVERTEX* pVertices; - int dwNumTriangles = 0L; - - D3D11_MAPPED_SUBRESOURCE vbmap; - HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); - if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; - - // if center was requested, set current position as centre - // this is currently never used - if (center) - { - const char *oldText = strText; - float mx=0; - float maxx=0; - - while (c = *strText++) - { - if (c == ('\n')) mx = 0; - if (c < (' ') ) continue; - c -= 32; - mx += (m_fTexCoords[c][2]-m_fTexCoords[c][0])/(m_fTexCoords[0][3] - m_fTexCoords[0][1]) + spacing; - if (mx > maxx) maxx = mx; - } - sx -= scalex*maxx*size; - strText = oldText; - } - // set general pipeline state - D3D::stateman->PushBlendState(m_blendstate); - D3D::stateman->PushRasterizerState(m_raststate); - D3D::stateman->Apply(); - - D3D::context->PSSetShader(m_pshader, NULL, 0); - D3D::context->VSSetShader(m_vshader, NULL, 0); - - D3D::context->IASetInputLayout(m_InputLayout); - D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::context->PSSetShaderResources(0, 1, &m_pTexture); - - float fStartX = sx; - while (c = *strText++) - { - if (c == ('\n')) - { - sx = fStartX; - sy -= scaley * size; - } - if (c < (' ')) continue; - - c -= 32; - float tx1 = m_fTexCoords[c][0]; - float ty1 = m_fTexCoords[c][1]; - float tx2 = m_fTexCoords[c][2]; - float ty2 = m_fTexCoords[c][3]; - - float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio; - float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio; - - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex( sx, h+sy, dwColor, tx1, ty2); - v[1] = InitFont2DVertex( sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(w+sx, h+sy, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(w+sx, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; - - memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); - - pVertices+=6; - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) - { - context->Unmap(m_pVB, 0); - - D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset); - D3D::context->Draw(3 * dwNumTriangles, 0); - - dwNumTriangles = 0; - D3D11_MAPPED_SUBRESOURCE vbmap; - hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); - if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); - pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; - } - sx += w + spacing * scalex * size; - } - - // Unlock and render the vertex buffer - context->Unmap(m_pVB, 0); - if (dwNumTriangles > 0) - { - D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset); - D3D::context->Draw(3 * dwNumTriangles, 0); - } - D3D::stateman->PopBlendState(); - D3D::stateman->PopRasterizerState(); - return S_OK; -} - -ID3D11Buffer* CreateQuadVertexBuffer(unsigned int size, void* data) -{ - ID3D11Buffer* vb; - D3D11_BUFFER_DESC vbdesc; - vbdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbdesc.ByteWidth = size; - vbdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbdesc.MiscFlags = 0; - vbdesc.Usage = D3D11_USAGE_DYNAMIC; - if (data) - { - D3D11_SUBRESOURCE_DATA bufdata; - bufdata.pSysMem = data; - if (FAILED(device->CreateBuffer(&vbdesc, &bufdata, &vb))) return NULL; - } - else if (FAILED(device->CreateBuffer(&vbdesc, NULL, &vb))) return NULL; - - return vb; -} - -ID3D11SamplerState* linear_copy_sampler = NULL; -ID3D11SamplerState* point_copy_sampler = NULL; -ID3D11Buffer* stqvb = NULL; -ID3D11Buffer* stsqvb = NULL; -ID3D11Buffer* clearvb = NULL; - -typedef struct { float x,y,z,u,v; } STQVertex; -typedef struct { float x,y,z,u,v; } STSQVertex; -typedef struct { float x,y,z; u32 col; } ClearVertex; - -struct -{ - float u1, v1, u2, v2; -} tex_quad_data; - -struct -{ - MathUtil::Rectangle rdest; - float u1, v1, u2, v2; -} tex_sub_quad_data; - -struct -{ - u32 col; - float z; -} clear_quad_data; - -void InitUtils() -{ - float border[4] = { 0.f, 0.f, 0.f, 0.f }; - D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); - HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler); - if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); - else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state"); - - samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); - hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler); - if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); - else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state"); - - // cached data used to avoid unnecessarily reloading the vertex buffers - memset(&tex_quad_data, 0, sizeof(tex_quad_data)); - memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data)); - memset(&clear_quad_data, 0, sizeof(clear_quad_data)); - - STQVertex stqcoords[4] = { - {-1.0f, 1.0f, 0.0f, 0, 0}, - { 1.0f, 1.0f, 0.0f, 0, 0}, - {-1.0f,-1.0f, 0.0f, 0, 0}, - { 1.0f,-1.0f, 0.0f, 0, 0}, - }; - - STSQVertex stsqcoords[4]; - memset(stsqcoords, 0, sizeof(stsqcoords)); - - ClearVertex cqcoords[4] = { - {-1.0f, 1.0f, 0, 0}, - { 1.0f, 1.0f, 0, 0}, - {-1.0f, -1.0f, 0, 0}, - { 1.0f, -1.0f, 0, 0}, - }; - - stqvb = CreateQuadVertexBuffer(4*sizeof(STQVertex), stqcoords); - CHECK(stqvb!=NULL, "Create vertex buffer of drawShadedTexQuad"); - SetDebugObjectName((ID3D11DeviceChild*)stqvb, "vertex buffer of drawShadedTexQuad"); - - stsqvb = CreateQuadVertexBuffer(4*sizeof(STSQVertex), stsqcoords); - CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad"); - SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad"); - - clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords); - CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad"); - SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad"); - - font.Init(); -} - -void ShutdownUtils() -{ - font.Shutdown(); - SAFE_RELEASE(point_copy_sampler); - SAFE_RELEASE(linear_copy_sampler); - SAFE_RELEASE(stqvb); - SAFE_RELEASE(stsqvb); - SAFE_RELEASE(clearvb); -} - -void SetPointCopySampler() -{ - D3D::context->PSSetSamplers(0, 1, &point_copy_sampler); -} - -void SetLinearCopySampler() -{ - D3D::context->PSSetSamplers(0, 1, &linear_copy_sampler); -} - -void drawShadedTexQuad(ID3D11ShaderResourceView* texture, - const D3D11_RECT* rSource, - int SourceWidth, - int SourceHeight, - ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, - ID3D11InputLayout* layout) -{ - float sw = 1.0f /(float) SourceWidth; - float sh = 1.0f /(float) SourceHeight; - float u1 = ((float)rSource->left) * sw; - float u2 = ((float)rSource->right) * sw; - float v1 = ((float)rSource->top) * sh; - float v2 = ((float)rSource->bottom) * sh; - - STQVertex coords[4] = { - {-1.0f, 1.0f, 0.0f, u1, v1}, - { 1.0f, 1.0f, 0.0f, u2, v1}, - {-1.0f,-1.0f, 0.0f, u1, v2}, - { 1.0f,-1.0f, 0.0f, u2, v2}, - }; - - // only upload the data to VRAM if it changed - if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || - tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(stqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, coords, sizeof(coords)); - D3D::context->Unmap(stqvb, 0); - tex_quad_data.u1 = u1; - tex_quad_data.v1 = v1; - tex_quad_data.u2 = u2; - tex_quad_data.v2 = v2; - } - UINT stride = sizeof(STQVertex); - UINT offset = 0; - - D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - D3D::context->IASetInputLayout(layout); - D3D::context->IASetVertexBuffers(0, 1, &stqvb, &stride, &offset); - D3D::context->PSSetShader(PShader, NULL, 0); - D3D::context->PSSetShaderResources(0, 1, &texture); - D3D::context->VSSetShader(Vshader, NULL, 0); - D3D::stateman->Apply(); - D3D::context->Draw(4, 0); - - ID3D11ShaderResourceView* texres = NULL; - context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture -} - -void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, - const MathUtil::Rectangle* rSource, - int SourceWidth, - int SourceHeight, - const MathUtil::Rectangle* rDest, - ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, - ID3D11InputLayout* layout) -{ - float sw = 1.0f /(float) SourceWidth; - float sh = 1.0f /(float) SourceHeight; - float u1 = (rSource->left ) * sw; - float u2 = (rSource->right ) * sw; - float v1 = (rSource->top ) * sh; - float v2 = (rSource->bottom) * sh; - - STSQVertex coords[4] = { - { rDest->left , rDest->bottom, 0.0f, u1, v1}, - { rDest->right, rDest->bottom, 0.0f, u2, v1}, - { rDest->left , rDest->top , 0.0f, u1, v2}, - { rDest->right, rDest->top , 0.0f, u2, v2}, - }; - - // only upload the data to VRAM if it changed - if (memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(rDest)) != 0 || - tex_sub_quad_data.u1 != u1 || tex_sub_quad_data.v1 != v1 || - tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(stsqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, coords, sizeof(coords)); - D3D::context->Unmap(stsqvb, 0); - tex_sub_quad_data.u1 = u1; - tex_sub_quad_data.v1 = v1; - tex_sub_quad_data.u2 = u2; - tex_sub_quad_data.v2 = v2; - memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest)); - } - UINT stride = sizeof(STSQVertex); - UINT offset = 0; - - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context->IASetVertexBuffers(0, 1, &stsqvb, &stride, &offset); - context->IASetInputLayout(layout); - context->PSSetShaderResources(0, 1, &texture); - context->PSSetShader(PShader, NULL, 0); - context->VSSetShader(Vshader, NULL, 0); - stateman->Apply(); - context->Draw(4, 0); - - ID3D11ShaderResourceView* texres = NULL; - context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture -} - -void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout) -{ - if (clear_quad_data.col != Color || clear_quad_data.z != z) - { - const ClearVertex coords[4] = { - {-1.0f, 1.0f, z, Color}, - { 1.0f, 1.0f, z, Color}, - {-1.0f, -1.0f, z, Color}, - { 1.0f, -1.0f, z, Color}, - }; - - D3D11_MAPPED_SUBRESOURCE map; - context->Map(clearvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, coords, sizeof(coords)); - context->Unmap(clearvb, 0); - clear_quad_data.col = Color; - clear_quad_data.z = z; - } - context->VSSetShader(Vshader, NULL, 0); - context->PSSetShader(PShader, NULL, 0); - context->IASetInputLayout(layout); - - UINT stride = sizeof(ClearVertex); - UINT offset = 0; - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context->IASetVertexBuffers(0, 1, &clearvb, &stride, &offset); - stateman->Apply(); - context->Draw(4, 0); -} - - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "Common.h" + +// DX11 +#include "DX11_Render.h" +#include "DX11_D3DBase.h" +#include "DX11_D3DUtil.h" +#include "DX11_D3DTexture.h" +#include "DX11_PixelShaderCache.h" +#include "DX11_VertexShaderCache.h" +#include "DX11_D3DShader.h" + +namespace DX11 +{ + +namespace D3D +{ + +CD3DFont font; + +#define MAX_NUM_VERTICES 300 +struct FONT2DVERTEX { + float x,y,z; + float col[4]; + float tu, tv; +}; + +inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) +{ + FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv; + v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f; + v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f; + v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f; + v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f; + return v; +} + +CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512) +{ + m_pTexture = NULL; + m_pVB = NULL; + m_InputLayout = NULL; + m_pshader = NULL; + m_vshader = NULL; +} + +const char fontpixshader[] = { + "Texture2D tex2D;\n" + "SamplerState linearSampler\n" + "{\n" + " Filter = MIN_MAG_MIP_LINEAR;\n" + " AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n" + " BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "float4 main( PS_INPUT input ) : SV_Target\n" + "{\n" + " return tex2D.Sample( linearSampler, input.tex ) * input.col;\n" + "};\n" +}; + +const char fontvertshader[] = { + "struct VS_INPUT\n" + "{\n" + " float4 pos : POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "struct PS_INPUT\n" + "{\n" + " float4 pos : SV_POSITION;\n" + " float4 col : COLOR;\n" + " float2 tex : TEXCOORD;\n" + "};\n" + "PS_INPUT main( VS_INPUT input )\n" + "{\n" + " PS_INPUT output;\n" + " output.pos = input.pos;\n" + " output.col = input.col;\n" + " output.tex = input.tex;\n" + " return output;\n" + "};\n" +}; + +int CD3DFont::Init() +{ + HRESULT hr; + + // prepare to create a bitmap + unsigned int* pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + // create a DC and a bitmap for the font + HDC hDC = CreateCompatibleDC(NULL); + HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0); + SetMapMode(hDC, MM_TEXT); + + // create a GDI font + HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE, + FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, PROOF_QUALITY, + VARIABLE_PITCH, _T("Tahoma")); + if (NULL == hFont) return E_FAIL; + + HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); + HGDIOBJ hOldFont = SelectObject(hDC, hFont); + + // set text properties + SetTextColor(hDC, 0xFFFFFF); + SetBkColor (hDC, 0); + SetTextAlign(hDC, TA_TOP); + + TEXTMETRICW tm; + GetTextMetricsW(hDC, &tm); + m_LineHeight = tm.tmHeight; + + // loop through all printable characters and output them to the bitmap + // meanwhile, keep track of the corresponding tex coords for each character. + int x = 0, y = 0; + char str[2] = "\0"; + for (int c = 0; c < 127 - 32; c++) + { + str[0] = c + 32; + SIZE size; + GetTextExtentPoint32A(hDC, str, 1, &size); + if ((int)(x+size.cx+1) > m_dwTexWidth) + { + x = 0; + y += m_LineHeight; + } + + ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); + m_fTexCoords[c][0] = (float) x /m_dwTexWidth; + m_fTexCoords[c][1] = (float) y /m_dwTexHeight; + m_fTexCoords[c][2] = (float)(x+size.cx)/m_dwTexWidth; + m_fTexCoords[c][3] = (float)(y+size.cy)/m_dwTexHeight; + + x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i) + } + + // create a new texture for the font + // possible optimization: store the converted data in a buffer and fill the texture on creation. + // That way, we can use a static texture + ID3D11Texture2D* buftex; + D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight, + 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC, + D3D11_CPU_ACCESS_WRITE); + hr = device->CreateTexture2D(&texdesc, NULL, &buftex); + if (FAILED(hr)) + { + PanicAlert("Failed to create font texture"); + return hr; + } + D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object"); + + // lock the surface and write the alpha values for the set pixels + D3D11_MAPPED_SUBRESOURCE texmap; + hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap); + if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__); + + for (y = 0; y < m_dwTexHeight; y++) + { + u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch); + for (x = 0; x < m_dwTexWidth; x++) + { + const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff); + *pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF; + } + } + + // clean up + context->Unmap(buftex, 0); + hr = D3D::device->CreateShaderResourceView(buftex, NULL, &m_pTexture); + if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__); + SAFE_RELEASE(buftex); + + SelectObject(hDC, hOldbmBitmap); + DeleteObject(hbmBitmap); + + SelectObject(hDC, hOldFont); + DeleteObject(hFont); + + // setup device objects for drawing + m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader, sizeof(fontpixshader)); + if (m_pshader == NULL) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object"); + + D3DBlob* vsbytecode; + D3D::CompileVertexShader(fontvertshader, sizeof(fontvertshader), &vsbytecode); + if (vsbytecode == NULL) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__); + m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode); + if (m_vshader == NULL) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object"); + + const D3D11_INPUT_ELEMENT_DESC desc[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout); + if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); + SAFE_RELEASE(vsbytecode); + + D3D11_BLEND_DESC blenddesc; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = TRUE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate); + CHECK(hr==S_OK, "Create font blend state"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object"); + + // this might need to be changed when adding multisampling support + D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false); + hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate); + CHECK(hr==S_OK, "Create font rasterizer state"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object"); + + D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + if (FAILED(hr = device->CreateBuffer(&vbdesc, NULL, &m_pVB))) + { + PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__); + return hr; + } + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object"); + return S_OK; +} + +int CD3DFont::Shutdown() +{ + SAFE_RELEASE(m_pVB); + SAFE_RELEASE(m_pTexture); + SAFE_RELEASE(m_InputLayout); + SAFE_RELEASE(m_pshader); + SAFE_RELEASE(m_vshader); + + SAFE_RELEASE(m_blendstate); + SAFE_RELEASE(m_raststate); + + return S_OK; +} + +int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const char* strText, bool center) +{ + if (!m_pVB) return 0; + + UINT stride = sizeof(FONT2DVERTEX); + UINT bufoffset = 0; + + float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f; + float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f; + float sizeratio = size / (float)m_LineHeight; + + // translate starting positions + float sx = x * scalex - 1.f; + float sy = 1.f - y * scaley; + char c; + + // fill vertex buffer + FONT2DVERTEX* pVertices; + int dwNumTriangles = 0L; + + D3D11_MAPPED_SUBRESOURCE vbmap; + HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); + if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); + pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; + + // if center was requested, set current position as centre + // this is currently never used + if (center) + { + const char *oldText = strText; + float mx=0; + float maxx=0; + + while (c = *strText++) + { + if (c == ('\n')) mx = 0; + if (c < (' ') ) continue; + c -= 32; + mx += (m_fTexCoords[c][2]-m_fTexCoords[c][0])/(m_fTexCoords[0][3] - m_fTexCoords[0][1]) + spacing; + if (mx > maxx) maxx = mx; + } + sx -= scalex*maxx*size; + strText = oldText; + } + // set general pipeline state + D3D::stateman->PushBlendState(m_blendstate); + D3D::stateman->PushRasterizerState(m_raststate); + D3D::stateman->Apply(); + + D3D::context->PSSetShader(m_pshader, NULL, 0); + D3D::context->VSSetShader(m_vshader, NULL, 0); + + D3D::context->IASetInputLayout(m_InputLayout); + D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::context->PSSetShaderResources(0, 1, &m_pTexture); + + float fStartX = sx; + while (c = *strText++) + { + if (c == ('\n')) + { + sx = fStartX; + sy -= scaley * size; + } + if (c < (' ')) continue; + + c -= 32; + float tx1 = m_fTexCoords[c][0]; + float ty1 = m_fTexCoords[c][1]; + float tx2 = m_fTexCoords[c][2]; + float ty2 = m_fTexCoords[c][3]; + + float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio; + float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio; + + FONT2DVERTEX v[6]; + v[0] = InitFont2DVertex( sx, h+sy, dwColor, tx1, ty2); + v[1] = InitFont2DVertex( sx, sy, dwColor, tx1, ty1); + v[2] = InitFont2DVertex(w+sx, h+sy, dwColor, tx2, ty2); + v[3] = InitFont2DVertex(w+sx, sy, dwColor, tx2, ty1); + v[4] = v[2]; + v[5] = v[1]; + + memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); + + pVertices+=6; + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) + { + context->Unmap(m_pVB, 0); + + D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset); + D3D::context->Draw(3 * dwNumTriangles, 0); + + dwNumTriangles = 0; + D3D11_MAPPED_SUBRESOURCE vbmap; + hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap); + if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__); + pVertices = (D3D::FONT2DVERTEX*)vbmap.pData; + } + sx += w + spacing * scalex * size; + } + + // Unlock and render the vertex buffer + context->Unmap(m_pVB, 0); + if (dwNumTriangles > 0) + { + D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset); + D3D::context->Draw(3 * dwNumTriangles, 0); + } + D3D::stateman->PopBlendState(); + D3D::stateman->PopRasterizerState(); + return S_OK; +} + +ID3D11Buffer* CreateQuadVertexBuffer(unsigned int size, void* data) +{ + ID3D11Buffer* vb; + D3D11_BUFFER_DESC vbdesc; + vbdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbdesc.ByteWidth = size; + vbdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbdesc.MiscFlags = 0; + vbdesc.Usage = D3D11_USAGE_DYNAMIC; + if (data) + { + D3D11_SUBRESOURCE_DATA bufdata; + bufdata.pSysMem = data; + if (FAILED(device->CreateBuffer(&vbdesc, &bufdata, &vb))) return NULL; + } + else if (FAILED(device->CreateBuffer(&vbdesc, NULL, &vb))) return NULL; + + return vb; +} + +ID3D11SamplerState* linear_copy_sampler = NULL; +ID3D11SamplerState* point_copy_sampler = NULL; +ID3D11Buffer* stqvb = NULL; +ID3D11Buffer* stsqvb = NULL; +ID3D11Buffer* clearvb = NULL; + +typedef struct { float x,y,z,u,v; } STQVertex; +typedef struct { float x,y,z,u,v; } STSQVertex; +typedef struct { float x,y,z; u32 col; } ClearVertex; + +struct +{ + float u1, v1, u2, v2; +} tex_quad_data; + +struct +{ + MathUtil::Rectangle rdest; + float u1, v1, u2, v2; +} tex_sub_quad_data; + +struct +{ + u32 col; + float z; +} clear_quad_data; + +void InitUtils() +{ + float border[4] = { 0.f, 0.f, 0.f, 0.f }; + D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); + HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler); + if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); + else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state"); + + samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); + hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler); + if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__); + else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state"); + + // cached data used to avoid unnecessarily reloading the vertex buffers + memset(&tex_quad_data, 0, sizeof(tex_quad_data)); + memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data)); + memset(&clear_quad_data, 0, sizeof(clear_quad_data)); + + STQVertex stqcoords[4] = { + {-1.0f, 1.0f, 0.0f, 0, 0}, + { 1.0f, 1.0f, 0.0f, 0, 0}, + {-1.0f,-1.0f, 0.0f, 0, 0}, + { 1.0f,-1.0f, 0.0f, 0, 0}, + }; + + STSQVertex stsqcoords[4]; + memset(stsqcoords, 0, sizeof(stsqcoords)); + + ClearVertex cqcoords[4] = { + {-1.0f, 1.0f, 0, 0}, + { 1.0f, 1.0f, 0, 0}, + {-1.0f, -1.0f, 0, 0}, + { 1.0f, -1.0f, 0, 0}, + }; + + stqvb = CreateQuadVertexBuffer(4*sizeof(STQVertex), stqcoords); + CHECK(stqvb!=NULL, "Create vertex buffer of drawShadedTexQuad"); + SetDebugObjectName((ID3D11DeviceChild*)stqvb, "vertex buffer of drawShadedTexQuad"); + + stsqvb = CreateQuadVertexBuffer(4*sizeof(STSQVertex), stsqcoords); + CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad"); + SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad"); + + clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords); + CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad"); + SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad"); + + font.Init(); +} + +void ShutdownUtils() +{ + font.Shutdown(); + SAFE_RELEASE(point_copy_sampler); + SAFE_RELEASE(linear_copy_sampler); + SAFE_RELEASE(stqvb); + SAFE_RELEASE(stsqvb); + SAFE_RELEASE(clearvb); +} + +void SetPointCopySampler() +{ + D3D::context->PSSetSamplers(0, 1, &point_copy_sampler); +} + +void SetLinearCopySampler() +{ + D3D::context->PSSetSamplers(0, 1, &linear_copy_sampler); +} + +void drawShadedTexQuad(ID3D11ShaderResourceView* texture, + const D3D11_RECT* rSource, + int SourceWidth, + int SourceHeight, + ID3D11PixelShader* PShader, + ID3D11VertexShader* Vshader, + ID3D11InputLayout* layout) +{ + float sw = 1.0f /(float) SourceWidth; + float sh = 1.0f /(float) SourceHeight; + float u1 = ((float)rSource->left) * sw; + float u2 = ((float)rSource->right) * sw; + float v1 = ((float)rSource->top) * sh; + float v2 = ((float)rSource->bottom) * sh; + + STQVertex coords[4] = { + {-1.0f, 1.0f, 0.0f, u1, v1}, + { 1.0f, 1.0f, 0.0f, u2, v1}, + {-1.0f,-1.0f, 0.0f, u1, v2}, + { 1.0f,-1.0f, 0.0f, u2, v2}, + }; + + // only upload the data to VRAM if it changed + if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || + tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(stqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, coords, sizeof(coords)); + D3D::context->Unmap(stqvb, 0); + tex_quad_data.u1 = u1; + tex_quad_data.v1 = v1; + tex_quad_data.u2 = u2; + tex_quad_data.v2 = v2; + } + UINT stride = sizeof(STQVertex); + UINT offset = 0; + + D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::context->IASetInputLayout(layout); + D3D::context->IASetVertexBuffers(0, 1, &stqvb, &stride, &offset); + D3D::context->PSSetShader(PShader, NULL, 0); + D3D::context->PSSetShaderResources(0, 1, &texture); + D3D::context->VSSetShader(Vshader, NULL, 0); + D3D::stateman->Apply(); + D3D::context->Draw(4, 0); + + ID3D11ShaderResourceView* texres = NULL; + context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture +} + +void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, + const MathUtil::Rectangle* rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle* rDest, + ID3D11PixelShader* PShader, + ID3D11VertexShader* Vshader, + ID3D11InputLayout* layout) +{ + float sw = 1.0f /(float) SourceWidth; + float sh = 1.0f /(float) SourceHeight; + float u1 = (rSource->left ) * sw; + float u2 = (rSource->right ) * sw; + float v1 = (rSource->top ) * sh; + float v2 = (rSource->bottom) * sh; + + STSQVertex coords[4] = { + { rDest->left , rDest->bottom, 0.0f, u1, v1}, + { rDest->right, rDest->bottom, 0.0f, u2, v1}, + { rDest->left , rDest->top , 0.0f, u1, v2}, + { rDest->right, rDest->top , 0.0f, u2, v2}, + }; + + // only upload the data to VRAM if it changed + if (memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(rDest)) != 0 || + tex_sub_quad_data.u1 != u1 || tex_sub_quad_data.v1 != v1 || + tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(stsqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, coords, sizeof(coords)); + D3D::context->Unmap(stsqvb, 0); + tex_sub_quad_data.u1 = u1; + tex_sub_quad_data.v1 = v1; + tex_sub_quad_data.u2 = u2; + tex_sub_quad_data.v2 = v2; + memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest)); + } + UINT stride = sizeof(STSQVertex); + UINT offset = 0; + + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context->IASetVertexBuffers(0, 1, &stsqvb, &stride, &offset); + context->IASetInputLayout(layout); + context->PSSetShaderResources(0, 1, &texture); + context->PSSetShader(PShader, NULL, 0); + context->VSSetShader(Vshader, NULL, 0); + stateman->Apply(); + context->Draw(4, 0); + + ID3D11ShaderResourceView* texres = NULL; + context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture +} + +void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout) +{ + if (clear_quad_data.col != Color || clear_quad_data.z != z) + { + const ClearVertex coords[4] = { + {-1.0f, 1.0f, z, Color}, + { 1.0f, 1.0f, z, Color}, + {-1.0f, -1.0f, z, Color}, + { 1.0f, -1.0f, z, Color}, + }; + + D3D11_MAPPED_SUBRESOURCE map; + context->Map(clearvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, coords, sizeof(coords)); + context->Unmap(clearvb, 0); + clear_quad_data.col = Color; + clear_quad_data.z = z; + } + context->VSSetShader(Vshader, NULL, 0); + context->PSSetShader(PShader, NULL, 0); + context->IASetInputLayout(layout); + + UINT stride = sizeof(ClearVertex); + UINT offset = 0; + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context->IASetVertexBuffers(0, 1, &clearvb, &stride, &offset); + stateman->Apply(); + context->Draw(4, 0); +} + + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.h index 0e7ad0ac77..487a84724f 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_D3DUtil.h @@ -1,91 +1,91 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include -#include - -#include "DX11_D3DBase.h" - -namespace DX11 -{ - -namespace D3D -{ - // Font creation flags - #define D3DFONT_BOLD 0x0001 - #define D3DFONT_ITALIC 0x0002 - - // Font rendering flags - #define D3DFONT_CENTERED 0x0001 - - class CD3DFont - { - ID3D11ShaderResourceView* m_pTexture; - ID3D11Buffer* m_pVB; - ID3D11InputLayout* m_InputLayout; - ID3D11PixelShader* m_pshader; - ID3D11VertexShader* m_vshader; - ID3D11BlendState* m_blendstate; - ID3D11RasterizerState* m_raststate; - const int m_dwTexWidth; - const int m_dwTexHeight; - unsigned int m_LineHeight; - float m_fTexCoords[128-32][4]; - - public: - CD3DFont(); - // 2D text drawing function - // Initializing and destroying device-dependent objects - int Init(); - int Shutdown(); - int DrawTextScaled(float x, float y, - float size, - float spacing, u32 dwColor, - const char* strText, bool center=true); - }; - - extern CD3DFont font; - - void InitUtils(); - void ShutdownUtils(); - - void SetPointCopySampler(); - void SetLinearCopySampler(); - - void drawShadedTexQuad(ID3D11ShaderResourceView* texture, - const D3D11_RECT* rSource, - int SourceWidth, - int SourceHeight, - ID3D11PixelShader* PShader, - ID3D11VertexShader* VShader, - ID3D11InputLayout* layout); - void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, - const MathUtil::Rectangle* rSource, - int SourceWidth, - int SourceHeight, - const MathUtil::Rectangle* rDest, - ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, - ID3D11InputLayout* layout); - void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout); - void SaveRenderStates(); - void RestoreRenderStates(); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include +#include + +#include "DX11_D3DBase.h" + +namespace DX11 +{ + +namespace D3D +{ + // Font creation flags + #define D3DFONT_BOLD 0x0001 + #define D3DFONT_ITALIC 0x0002 + + // Font rendering flags + #define D3DFONT_CENTERED 0x0001 + + class CD3DFont + { + ID3D11ShaderResourceView* m_pTexture; + ID3D11Buffer* m_pVB; + ID3D11InputLayout* m_InputLayout; + ID3D11PixelShader* m_pshader; + ID3D11VertexShader* m_vshader; + ID3D11BlendState* m_blendstate; + ID3D11RasterizerState* m_raststate; + const int m_dwTexWidth; + const int m_dwTexHeight; + unsigned int m_LineHeight; + float m_fTexCoords[128-32][4]; + + public: + CD3DFont(); + // 2D text drawing function + // Initializing and destroying device-dependent objects + int Init(); + int Shutdown(); + int DrawTextScaled(float x, float y, + float size, + float spacing, u32 dwColor, + const char* strText, bool center=true); + }; + + extern CD3DFont font; + + void InitUtils(); + void ShutdownUtils(); + + void SetPointCopySampler(); + void SetLinearCopySampler(); + + void drawShadedTexQuad(ID3D11ShaderResourceView* texture, + const D3D11_RECT* rSource, + int SourceWidth, + int SourceHeight, + ID3D11PixelShader* PShader, + ID3D11VertexShader* VShader, + ID3D11InputLayout* layout); + void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, + const MathUtil::Rectangle* rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle* rDest, + ID3D11PixelShader* PShader, + ID3D11VertexShader* Vshader, + ID3D11InputLayout* layout); + void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout); + void SaveRenderStates(); + void RestoreRenderStates(); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.cpp index 5a4d6562e3..b345cee502 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.cpp @@ -1,162 +1,162 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// VideoCommon -#include "VideoConfig.h" - -// DX11 -#include "DX11_Render.h" -#include "DX11_D3DBase.h" -#include "DX11_D3DTexture.h" -#include "DX11_D3DUtil.h" -#include "DX11_FramebufferManager.h" -#include "DX11_PixelShaderCache.h" -#include "DX11_VertexShaderCache.h" - -#include "../Main.h" - -namespace DX11 -{ - -XFBSource FramebufferManager::m_realXFBSource; // used in real XFB mode - -FramebufferManager::EFB FramebufferManager::m_efb; - -D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; } -ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; } - -D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; } -D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; } -ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; } - -FramebufferManager::FramebufferManager() -{ - m_efb.color_tex = NULL; - m_efb.color_staging_buf = NULL; - m_efb.depth_tex = NULL; - m_efb.depth_staging_buf = NULL; - m_efb.depth_read_texture = NULL; - - m_realXFBSource.tex = NULL; - - unsigned int target_width = Renderer::GetFullTargetWidth(); - unsigned int target_height = Renderer::GetFullTargetHeight(); - ID3D11Texture2D* buf; - D3D11_TEXTURE2D_DESC texdesc; - HRESULT hr; - - // create framebuffer color texture - m_efb.color_tex = D3DTexture2D::Create(target_width, target_height, - (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM); - CHECK(m_efb.color_tex, "create EFB color texture (size: %dx%d)", target_width, target_height); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view"); - - // create a staging texture for Renderer::AccessEFB - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, - D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_WRITE|D3D11_CPU_ACCESS_READ); - hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.color_staging_buf); - CHECK(SUCCEEDED(hr), "create EFB color staging buffer (hr=%#x)", hr); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)"); - - // EFB depth buffer - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, - target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE); - hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf); - CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); - m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE), - DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view"); - - // render target for depth buffer access in Renderer::AccessEFB - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf); - CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr); - m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); - SAFE_RELEASE(buf); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)"); - - // staging texture to which we copy the data from m_efb.depth_read_texture - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); - hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.depth_staging_buf); - CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr); - D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)"); -} - -FramebufferManager::~FramebufferManager() -{ - SAFE_RELEASE(m_efb.color_tex); - SAFE_RELEASE(m_efb.color_staging_buf); - SAFE_RELEASE(m_efb.depth_tex); - SAFE_RELEASE(m_efb.depth_staging_buf); - SAFE_RELEASE(m_efb.depth_read_texture); - - SAFE_RELEASE(m_realXFBSource.tex); -} - -void XFBSource::CopyEFB(const TargetRectangle& efbSource) -{ - // copy EFB data to XFB and restore render target again - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL); - D3D::SetLinearCopySampler(); - - D3DTexture2D* const ctex = FramebufferManager::GetEFBColorTexture(); - - D3D::drawShadedTexQuad(ctex->GetSRV(), efbSource.AsRECT(), - Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), - PixelShaderCache::GetColorCopyProgram(), VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); - - D3D::context->OMSetRenderTargets(1, &ctex->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); -} - -XFBSource::~XFBSource() -{ - tex->Release(); -} - -XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) -{ - XFBSource* const xfbs = new XFBSource; - xfbs->tex = D3DTexture2D::Create(target_width, target_height, - (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM); - - return xfbs; -} - -void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - // TODO - PanicAlert("copyToRealXFB not implemented, yet\n"); -} - -const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) -{ - PanicAlert("getRealXFBSource not implemented, yet\n"); - return NULL; -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// VideoCommon +#include "VideoConfig.h" + +// DX11 +#include "DX11_Render.h" +#include "DX11_D3DBase.h" +#include "DX11_D3DTexture.h" +#include "DX11_D3DUtil.h" +#include "DX11_FramebufferManager.h" +#include "DX11_PixelShaderCache.h" +#include "DX11_VertexShaderCache.h" + +#include "../Main.h" + +namespace DX11 +{ + +XFBSource FramebufferManager::m_realXFBSource; // used in real XFB mode + +FramebufferManager::EFB FramebufferManager::m_efb; + +D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; } +ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; } + +D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; } +D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; } +ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; } + +FramebufferManager::FramebufferManager() +{ + m_efb.color_tex = NULL; + m_efb.color_staging_buf = NULL; + m_efb.depth_tex = NULL; + m_efb.depth_staging_buf = NULL; + m_efb.depth_read_texture = NULL; + + m_realXFBSource.tex = NULL; + + unsigned int target_width = Renderer::GetFullTargetWidth(); + unsigned int target_height = Renderer::GetFullTargetHeight(); + ID3D11Texture2D* buf; + D3D11_TEXTURE2D_DESC texdesc; + HRESULT hr; + + // create framebuffer color texture + m_efb.color_tex = D3DTexture2D::Create(target_width, target_height, + (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE), + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM); + CHECK(m_efb.color_tex, "create EFB color texture (size: %dx%d)", target_width, target_height); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view"); + + // create a staging texture for Renderer::AccessEFB + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, + D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_WRITE|D3D11_CPU_ACCESS_READ); + hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.color_staging_buf); + CHECK(SUCCEEDED(hr), "create EFB color staging buffer (hr=%#x)", hr); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)"); + + // EFB depth buffer + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, + target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE); + hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf); + CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); + m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE), + DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view"); + + // render target for depth buffer access in Renderer::AccessEFB + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, D3D11_BIND_RENDER_TARGET); + hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf); + CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr); + m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); + SAFE_RELEASE(buf); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)"); + + // staging texture to which we copy the data from m_efb.depth_read_texture + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); + hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.depth_staging_buf); + CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr); + D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)"); +} + +FramebufferManager::~FramebufferManager() +{ + SAFE_RELEASE(m_efb.color_tex); + SAFE_RELEASE(m_efb.color_staging_buf); + SAFE_RELEASE(m_efb.depth_tex); + SAFE_RELEASE(m_efb.depth_staging_buf); + SAFE_RELEASE(m_efb.depth_read_texture); + + SAFE_RELEASE(m_realXFBSource.tex); +} + +void XFBSource::CopyEFB(const TargetRectangle& efbSource) +{ + // copy EFB data to XFB and restore render target again + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL); + D3D::SetLinearCopySampler(); + + D3DTexture2D* const ctex = FramebufferManager::GetEFBColorTexture(); + + D3D::drawShadedTexQuad(ctex->GetSRV(), efbSource.AsRECT(), + Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), + PixelShaderCache::GetColorCopyProgram(), VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout()); + + D3D::context->OMSetRenderTargets(1, &ctex->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); +} + +XFBSource::~XFBSource() +{ + tex->Release(); +} + +XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) +{ + XFBSource* const xfbs = new XFBSource; + xfbs->tex = D3DTexture2D::Create(target_width, target_height, + (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM); + + return xfbs; +} + +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + // TODO + PanicAlert("copyToRealXFB not implemented, yet\n"); +} + +const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + PanicAlert("getRealXFBSource not implemented, yet\n"); + return NULL; +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.h index 3a0179bdbd..8ff14891e3 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_FramebufferManager.h @@ -1,108 +1,108 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DX11_FBMANAGER_D3D_H_ -#define _DX11_FBMANAGER_D3D_H_ - -#include - -#include "DX11_D3DBase.h" - -#include "../FramebufferManager.h" - -namespace DX11 -{ - -// On the GameCube, the game sends a request for the graphics processor to -// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM -// called the XFB (External Framebuffer). The size and location of the XFB is -// decided at the time of the copy, and the format is always YUYV. The video -// interface is given a pointer to the XFB, which will be decoded and -// displayed on the TV. -// -// There are two ways for Dolphin to emulate this: -// -// Real XFB mode: -// -// Dolphin will behave like the GameCube and encode the EFB to -// a portion of GameCube RAM. The emulated video interface will decode the data -// for output to the screen. -// -// Advantages: Behaves exactly like the GameCube. -// Disadvantages: Resolution will be limited. -// -// Virtual XFB mode: -// -// When a request is made to copy the EFB to an XFB, Dolphin -// will remember the RAM location and size of the XFB in a Virtual XFB list. -// The video interface will look up the XFB in the list and use the enhanced -// data stored there, if available. -// -// Advantages: Enables high resolution graphics, better than real hardware. -// Disadvantages: If the GameCube CPU writes directly to the XFB (which is -// possible but uncommon), the Virtual XFB will not capture this information. - -// There may be multiple XFBs in GameCube RAM. This is the maximum number to -// virtualize. - -struct XFBSource : public XFBSourceBase -{ - XFBSource() : tex(NULL) {} - ~XFBSource(); - - void CopyEFB(const TargetRectangle& efbSource); - - D3DTexture2D* tex; -}; - -class FramebufferManager : public ::FramebufferManagerBase -{ - friend struct XFBSource; - -public: - FramebufferManager(); - ~FramebufferManager(); - - static D3DTexture2D* &GetEFBColorTexture(); - static ID3D11Texture2D* &GetEFBColorStagingBuffer(); - - static D3DTexture2D* &GetEFBDepthTexture(); - static D3DTexture2D* &GetEFBDepthReadTexture(); - static ID3D11Texture2D* &GetEFBDepthStagingBuffer(); - - XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height); - -private: - static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - static const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); - - static XFBSource m_realXFBSource; // used in real XFB mode - - static struct EFB - { - D3DTexture2D* color_tex; - ID3D11Texture2D* color_staging_buf; - - D3DTexture2D* depth_tex; - ID3D11Texture2D* depth_staging_buf; - D3DTexture2D* depth_read_texture; - } m_efb; -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DX11_FBMANAGER_D3D_H_ +#define _DX11_FBMANAGER_D3D_H_ + +#include + +#include "DX11_D3DBase.h" + +#include "../FramebufferManager.h" + +namespace DX11 +{ + +// On the GameCube, the game sends a request for the graphics processor to +// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM +// called the XFB (External Framebuffer). The size and location of the XFB is +// decided at the time of the copy, and the format is always YUYV. The video +// interface is given a pointer to the XFB, which will be decoded and +// displayed on the TV. +// +// There are two ways for Dolphin to emulate this: +// +// Real XFB mode: +// +// Dolphin will behave like the GameCube and encode the EFB to +// a portion of GameCube RAM. The emulated video interface will decode the data +// for output to the screen. +// +// Advantages: Behaves exactly like the GameCube. +// Disadvantages: Resolution will be limited. +// +// Virtual XFB mode: +// +// When a request is made to copy the EFB to an XFB, Dolphin +// will remember the RAM location and size of the XFB in a Virtual XFB list. +// The video interface will look up the XFB in the list and use the enhanced +// data stored there, if available. +// +// Advantages: Enables high resolution graphics, better than real hardware. +// Disadvantages: If the GameCube CPU writes directly to the XFB (which is +// possible but uncommon), the Virtual XFB will not capture this information. + +// There may be multiple XFBs in GameCube RAM. This is the maximum number to +// virtualize. + +struct XFBSource : public XFBSourceBase +{ + XFBSource() : tex(NULL) {} + ~XFBSource(); + + void CopyEFB(const TargetRectangle& efbSource); + + D3DTexture2D* tex; +}; + +class FramebufferManager : public ::FramebufferManagerBase +{ + friend struct XFBSource; + +public: + FramebufferManager(); + ~FramebufferManager(); + + static D3DTexture2D* &GetEFBColorTexture(); + static ID3D11Texture2D* &GetEFBColorStagingBuffer(); + + static D3DTexture2D* &GetEFBDepthTexture(); + static D3DTexture2D* &GetEFBDepthReadTexture(); + static ID3D11Texture2D* &GetEFBDepthStagingBuffer(); + + XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height); + +private: + static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + static const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + + static XFBSource m_realXFBSource; // used in real XFB mode + + static struct EFB + { + D3DTexture2D* color_tex; + ID3D11Texture2D* color_staging_buf; + + D3DTexture2D* depth_tex; + ID3D11Texture2D* depth_staging_buf; + D3DTexture2D* depth_read_texture; + } m_efb; +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.cpp index 79ed26815d..c9b32e8455 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.cpp @@ -1,372 +1,372 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "VideoConfig.h" -#include "DX11_GfxState.h" - -namespace DX11 -{ - -namespace D3D -{ - -EmuGfxState* gfxstate; -StateManager* stateman; - -EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(NULL), psbytecode(NULL), apply_called(false) -{ - for (unsigned int k = 0;k < 8;k++) - { - float border[4] = {0.f, 0.f, 0.f, 0.f}; - shader_resources[k] = NULL; - samplerdesc[k] = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, 0.f, 16, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); - if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC; - } - - memset(&blenddesc, 0, sizeof(blenddesc)); - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = FALSE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - - memset(&depthdesc, 0, sizeof(depthdesc)); - depthdesc.DepthEnable = TRUE; - depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthdesc.DepthFunc = D3D11_COMPARISON_LESS; - depthdesc.StencilEnable = FALSE; - depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - - // this probably must be changed once multisampling support gets added - rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false); - - pscbuf = NULL; - vscbuf = NULL; - vshaderchanged = false; - inp_layout = NULL; - num_inp_elems = 0; - - pscbufchanged = false; - vscbufchanged = false; -} - -EmuGfxState::~EmuGfxState() -{ - for (unsigned int k = 0;k < 8;k++) - SAFE_RELEASE(shader_resources[k]) - - SAFE_RELEASE(vsbytecode); - SAFE_RELEASE(psbytecode); - SAFE_RELEASE(vertexshader); - SAFE_RELEASE(pixelshader); - - SAFE_RELEASE(pscbuf); - SAFE_RELEASE(vscbuf); - - SAFE_RELEASE(inp_layout); -} - -// TODO: No need to store the whole bytecode, signature might be enough (?) -void EmuGfxState::SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode) -{ - // TODO: vshaderchanged actually just needs to be true if the signature changed - if (bcode && vsbytecode != bcode) vshaderchanged = true; - SAFE_RELEASE(vsbytecode); - SAFE_RELEASE(vertexshader); - - if (shader && bcode) - { - vertexshader = shader; - shader->AddRef(); - vsbytecode = bcode; - bcode->AddRef(); - } - else if (shader || bcode) - { - PanicAlert("Invalid parameters!\n"); - } -} - -void EmuGfxState::SetPShader(ID3D11PixelShader* shader) -{ - if (pixelshader) pixelshader->Release(); - pixelshader = shader; - if (shader) shader->AddRef(); -} - -void EmuGfxState::SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num) -{ - num_inp_elems = num; - memcpy(inp_elems, elems, num*sizeof(D3D11_INPUT_ELEMENT_DESC)); -} - -void EmuGfxState::SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv) -{ - if (shader_resources[stage]) - shader_resources[stage]->Release(); - shader_resources[stage] = srv; - if (srv) - srv->AddRef(); -} - -void EmuGfxState::ApplyState() -{ - HRESULT hr; - - // input layout (only needs to be updated if the vertex shader signature changed) - if (vshaderchanged) - { - SAFE_RELEASE(inp_layout); - hr = D3D::device->CreateInputLayout(inp_elems, num_inp_elems, vsbytecode->Data(), vsbytecode->Size(), &inp_layout); - if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - SetDebugObjectName((ID3D11DeviceChild*)inp_layout, "an input layout of EmuGfxState"); - vshaderchanged = false; - } - D3D::context->IASetInputLayout(inp_layout); - - // vertex shader - // TODO: divide the global variables of the generated shaders into about 5 constant buffers - // TODO: improve interaction between EmuGfxState and global state management, so that we don't need to set the constant buffers every time - if (!vscbuf) - { - unsigned int size = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - hr = device->CreateBuffer(&cbdesc, NULL, &vscbuf); - CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", size); - SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "a vertex shader constant buffer of EmuGfxState"); - } - if (vscbufchanged) - { - D3D11_MAPPED_SUBRESOURCE map; - context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, vsconstants, sizeof(vsconstants)); - context->Unmap(vscbuf, 0); - } - D3D::context->VSSetConstantBuffers(0, 1, &vscbuf); - - // pixel shader - if (!pscbuf) - { - unsigned int size = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - device->CreateBuffer(&cbdesc, NULL, &pscbuf); - CHECK(hr==S_OK, "Create pixel shader constant buffer (size=%u)", size); - SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "a pixel shader constant buffer of EmuGfxState"); - } - if (pscbufchanged) - { - D3D11_MAPPED_SUBRESOURCE map; - context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, psconstants, sizeof(psconstants)); - context->Unmap(pscbuf, 0); - pscbufchanged = false; - } - D3D::context->PSSetConstantBuffers(0, 1, &pscbuf); - - ID3D11SamplerState* samplerstate[8]; - for (unsigned int stage = 0; stage < 8; stage++) - { - if (shader_resources[stage]) - { - if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[stage].Filter = D3D11_FILTER_ANISOTROPIC; - hr = D3D::device->CreateSamplerState(&samplerdesc[stage], &samplerstate[stage]); - if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage); - else SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "a sampler state of EmuGfxState"); - } - else samplerstate[stage] = NULL; - } - D3D::context->PSSetSamplers(0, 8, samplerstate); - for (unsigned int stage = 0; stage < 8; stage++) - SAFE_RELEASE(samplerstate[stage]); - - ID3D11BlendState* blstate; - hr = device->CreateBlendState(&blenddesc, &blstate); - if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - stateman->PushBlendState(blstate); - SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState"); - SAFE_RELEASE(blstate); - - rastdesc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID; - ID3D11RasterizerState* raststate; - hr = device->CreateRasterizerState(&rastdesc, &raststate); - if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - SetDebugObjectName((ID3D11DeviceChild*)raststate, "a rasterizer state of EmuGfxState"); - stateman->PushRasterizerState(raststate); - SAFE_RELEASE(raststate); - - ID3D11DepthStencilState* depth_state; - hr = device->CreateDepthStencilState(&depthdesc, &depth_state); - if (SUCCEEDED(hr)) SetDebugObjectName((ID3D11DeviceChild*)depth_state, "a depth-stencil state of EmuGfxState"); - else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - D3D::stateman->PushDepthState(depth_state); - SAFE_RELEASE(depth_state); - - context->PSSetShader(pixelshader, NULL, 0); - context->VSSetShader(vertexshader, NULL, 0); - context->PSSetShaderResources(0, 8, shader_resources); - - stateman->Apply(); - apply_called = true; -} - -void EmuGfxState::AlphaPass() -{ - if (!apply_called) ERROR_LOG(VIDEO, "EmuGfxState::AlphaPass called without having called ApplyState before!") - else stateman->PopBlendState(); - - // pixel shader for alpha pass is different, so update it - context->PSSetShader(pixelshader, NULL, 0); - - ID3D11BlendState* blstate; - D3D11_BLEND_DESC desc = blenddesc; - desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; - desc.RenderTarget[0].BlendEnable = FALSE; - HRESULT hr = device->CreateBlendState(&desc, &blstate); - if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState (created during alpha pass)"); - stateman->PushBlendState(blstate); - blstate->Release(); - - stateman->Apply(); -} - -void EmuGfxState::Reset() -{ - for (unsigned int k = 0;k < 8;k++) - SAFE_RELEASE(shader_resources[k]); - - context->PSSetShaderResources(0, 8, shader_resources); // unbind all textures - if (apply_called) - { - stateman->PopBlendState(); - stateman->PopDepthState(); - stateman->PopRasterizerState(); - apply_called = false; - } -} - -void EmuGfxState::SetAlphaBlendEnable(bool enable) -{ - blenddesc.RenderTarget[0].BlendEnable = enable; -} - -void EmuGfxState::SetRenderTargetWriteMask(UINT8 mask) -{ - blenddesc.RenderTarget[0].RenderTargetWriteMask = mask; -} - -void EmuGfxState::SetSrcBlend(D3D11_BLEND val) -{ - // TODO: Check whether e.g. the dest color check is needed here - blenddesc.RenderTarget[0].SrcBlend = val; - if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else blenddesc.RenderTarget[0].SrcBlendAlpha = val; -} - -void EmuGfxState::SetDestBlend(D3D11_BLEND val) -{ - // TODO: Check whether e.g. the source color check is needed here - blenddesc.RenderTarget[0].DestBlend = val; - if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; - else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; - else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; - else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - else blenddesc.RenderTarget[0].DestBlendAlpha = val; -} - -void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val) -{ - blenddesc.RenderTarget[0].BlendOp = val; - blenddesc.RenderTarget[0].BlendOpAlpha = val; -} - -void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter) -{ - samplerdesc[stage].Filter = filter; -} - -template AutoState::AutoState(const T* object) : state(object) -{ - ((IUnknown*)state)->AddRef(); -} - -template AutoState::AutoState(const AutoState &source) -{ - state = source.GetPtr(); - ((T*)state)->AddRef(); -} - -template AutoState::~AutoState() -{ - if(state) ((T*)state)->Release(); - state = NULL; -} - -StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {} - -void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); } -void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); } -void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); } -void StateManager::PopBlendState() { blendstates.pop(); } -void StateManager::PopDepthState() { depthstates.pop(); } -void StateManager::PopRasterizerState() { raststates.pop(); } - -void StateManager::Apply() -{ - if (!blendstates.empty()) - { - if (cur_blendstate != blendstates.top().GetPtr()) - { - cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr(); - D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without blend state!"); - - if (!depthstates.empty()) - { - if (cur_depthstate != depthstates.top().GetPtr()) - { - cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr(); - D3D::context->OMSetDepthStencilState(cur_depthstate, 0); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without depth state!"); - - if (!raststates.empty()) - { - if (cur_raststate != raststates.top().GetPtr()) - { - cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr(); - D3D::context->RSSetState(cur_raststate); - } - } - else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "VideoConfig.h" +#include "DX11_GfxState.h" + +namespace DX11 +{ + +namespace D3D +{ + +EmuGfxState* gfxstate; +StateManager* stateman; + +EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(NULL), psbytecode(NULL), apply_called(false) +{ + for (unsigned int k = 0;k < 8;k++) + { + float border[4] = {0.f, 0.f, 0.f, 0.f}; + shader_resources[k] = NULL; + samplerdesc[k] = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, 0.f, 16, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX); + if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC; + } + + memset(&blenddesc, 0, sizeof(blenddesc)); + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = FALSE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + + memset(&depthdesc, 0, sizeof(depthdesc)); + depthdesc.DepthEnable = TRUE; + depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthdesc.DepthFunc = D3D11_COMPARISON_LESS; + depthdesc.StencilEnable = FALSE; + depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + + // this probably must be changed once multisampling support gets added + rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false); + + pscbuf = NULL; + vscbuf = NULL; + vshaderchanged = false; + inp_layout = NULL; + num_inp_elems = 0; + + pscbufchanged = false; + vscbufchanged = false; +} + +EmuGfxState::~EmuGfxState() +{ + for (unsigned int k = 0;k < 8;k++) + SAFE_RELEASE(shader_resources[k]) + + SAFE_RELEASE(vsbytecode); + SAFE_RELEASE(psbytecode); + SAFE_RELEASE(vertexshader); + SAFE_RELEASE(pixelshader); + + SAFE_RELEASE(pscbuf); + SAFE_RELEASE(vscbuf); + + SAFE_RELEASE(inp_layout); +} + +// TODO: No need to store the whole bytecode, signature might be enough (?) +void EmuGfxState::SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode) +{ + // TODO: vshaderchanged actually just needs to be true if the signature changed + if (bcode && vsbytecode != bcode) vshaderchanged = true; + SAFE_RELEASE(vsbytecode); + SAFE_RELEASE(vertexshader); + + if (shader && bcode) + { + vertexshader = shader; + shader->AddRef(); + vsbytecode = bcode; + bcode->AddRef(); + } + else if (shader || bcode) + { + PanicAlert("Invalid parameters!\n"); + } +} + +void EmuGfxState::SetPShader(ID3D11PixelShader* shader) +{ + if (pixelshader) pixelshader->Release(); + pixelshader = shader; + if (shader) shader->AddRef(); +} + +void EmuGfxState::SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num) +{ + num_inp_elems = num; + memcpy(inp_elems, elems, num*sizeof(D3D11_INPUT_ELEMENT_DESC)); +} + +void EmuGfxState::SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv) +{ + if (shader_resources[stage]) + shader_resources[stage]->Release(); + shader_resources[stage] = srv; + if (srv) + srv->AddRef(); +} + +void EmuGfxState::ApplyState() +{ + HRESULT hr; + + // input layout (only needs to be updated if the vertex shader signature changed) + if (vshaderchanged) + { + SAFE_RELEASE(inp_layout); + hr = D3D::device->CreateInputLayout(inp_elems, num_inp_elems, vsbytecode->Data(), vsbytecode->Size(), &inp_layout); + if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); + SetDebugObjectName((ID3D11DeviceChild*)inp_layout, "an input layout of EmuGfxState"); + vshaderchanged = false; + } + D3D::context->IASetInputLayout(inp_layout); + + // vertex shader + // TODO: divide the global variables of the generated shaders into about 5 constant buffers + // TODO: improve interaction between EmuGfxState and global state management, so that we don't need to set the constant buffers every time + if (!vscbuf) + { + unsigned int size = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16 + D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + hr = device->CreateBuffer(&cbdesc, NULL, &vscbuf); + CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", size); + SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "a vertex shader constant buffer of EmuGfxState"); + } + if (vscbufchanged) + { + D3D11_MAPPED_SUBRESOURCE map; + context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, vsconstants, sizeof(vsconstants)); + context->Unmap(vscbuf, 0); + } + D3D::context->VSSetConstantBuffers(0, 1, &vscbuf); + + // pixel shader + if (!pscbuf) + { + unsigned int size = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16 + D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + device->CreateBuffer(&cbdesc, NULL, &pscbuf); + CHECK(hr==S_OK, "Create pixel shader constant buffer (size=%u)", size); + SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "a pixel shader constant buffer of EmuGfxState"); + } + if (pscbufchanged) + { + D3D11_MAPPED_SUBRESOURCE map; + context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, psconstants, sizeof(psconstants)); + context->Unmap(pscbuf, 0); + pscbufchanged = false; + } + D3D::context->PSSetConstantBuffers(0, 1, &pscbuf); + + ID3D11SamplerState* samplerstate[8]; + for (unsigned int stage = 0; stage < 8; stage++) + { + if (shader_resources[stage]) + { + if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[stage].Filter = D3D11_FILTER_ANISOTROPIC; + hr = D3D::device->CreateSamplerState(&samplerdesc[stage], &samplerstate[stage]); + if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage); + else SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "a sampler state of EmuGfxState"); + } + else samplerstate[stage] = NULL; + } + D3D::context->PSSetSamplers(0, 8, samplerstate); + for (unsigned int stage = 0; stage < 8; stage++) + SAFE_RELEASE(samplerstate[stage]); + + ID3D11BlendState* blstate; + hr = device->CreateBlendState(&blenddesc, &blstate); + if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + stateman->PushBlendState(blstate); + SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState"); + SAFE_RELEASE(blstate); + + rastdesc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID; + ID3D11RasterizerState* raststate; + hr = device->CreateRasterizerState(&rastdesc, &raststate); + if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); + SetDebugObjectName((ID3D11DeviceChild*)raststate, "a rasterizer state of EmuGfxState"); + stateman->PushRasterizerState(raststate); + SAFE_RELEASE(raststate); + + ID3D11DepthStencilState* depth_state; + hr = device->CreateDepthStencilState(&depthdesc, &depth_state); + if (SUCCEEDED(hr)) SetDebugObjectName((ID3D11DeviceChild*)depth_state, "a depth-stencil state of EmuGfxState"); + else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); + D3D::stateman->PushDepthState(depth_state); + SAFE_RELEASE(depth_state); + + context->PSSetShader(pixelshader, NULL, 0); + context->VSSetShader(vertexshader, NULL, 0); + context->PSSetShaderResources(0, 8, shader_resources); + + stateman->Apply(); + apply_called = true; +} + +void EmuGfxState::AlphaPass() +{ + if (!apply_called) ERROR_LOG(VIDEO, "EmuGfxState::AlphaPass called without having called ApplyState before!") + else stateman->PopBlendState(); + + // pixel shader for alpha pass is different, so update it + context->PSSetShader(pixelshader, NULL, 0); + + ID3D11BlendState* blstate; + D3D11_BLEND_DESC desc = blenddesc; + desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; + desc.RenderTarget[0].BlendEnable = FALSE; + HRESULT hr = device->CreateBlendState(&desc, &blstate); + if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); + SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState (created during alpha pass)"); + stateman->PushBlendState(blstate); + blstate->Release(); + + stateman->Apply(); +} + +void EmuGfxState::Reset() +{ + for (unsigned int k = 0;k < 8;k++) + SAFE_RELEASE(shader_resources[k]); + + context->PSSetShaderResources(0, 8, shader_resources); // unbind all textures + if (apply_called) + { + stateman->PopBlendState(); + stateman->PopDepthState(); + stateman->PopRasterizerState(); + apply_called = false; + } +} + +void EmuGfxState::SetAlphaBlendEnable(bool enable) +{ + blenddesc.RenderTarget[0].BlendEnable = enable; +} + +void EmuGfxState::SetRenderTargetWriteMask(UINT8 mask) +{ + blenddesc.RenderTarget[0].RenderTargetWriteMask = mask; +} + +void EmuGfxState::SetSrcBlend(D3D11_BLEND val) +{ + // TODO: Check whether e.g. the dest color check is needed here + blenddesc.RenderTarget[0].SrcBlend = val; + if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else blenddesc.RenderTarget[0].SrcBlendAlpha = val; +} + +void EmuGfxState::SetDestBlend(D3D11_BLEND val) +{ + // TODO: Check whether e.g. the source color check is needed here + blenddesc.RenderTarget[0].DestBlend = val; + if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA; + else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA; + else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; + else blenddesc.RenderTarget[0].DestBlendAlpha = val; +} + +void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val) +{ + blenddesc.RenderTarget[0].BlendOp = val; + blenddesc.RenderTarget[0].BlendOpAlpha = val; +} + +void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter) +{ + samplerdesc[stage].Filter = filter; +} + +template AutoState::AutoState(const T* object) : state(object) +{ + ((IUnknown*)state)->AddRef(); +} + +template AutoState::AutoState(const AutoState &source) +{ + state = source.GetPtr(); + ((T*)state)->AddRef(); +} + +template AutoState::~AutoState() +{ + if(state) ((T*)state)->Release(); + state = NULL; +} + +StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {} + +void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); } +void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); } +void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); } +void StateManager::PopBlendState() { blendstates.pop(); } +void StateManager::PopDepthState() { depthstates.pop(); } +void StateManager::PopRasterizerState() { raststates.pop(); } + +void StateManager::Apply() +{ + if (!blendstates.empty()) + { + if (cur_blendstate != blendstates.top().GetPtr()) + { + cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr(); + D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without blend state!"); + + if (!depthstates.empty()) + { + if (cur_depthstate != depthstates.top().GetPtr()) + { + cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr(); + D3D::context->OMSetDepthStencilState(cur_depthstate, 0); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without depth state!"); + + if (!raststates.empty()) + { + if (cur_raststate != raststates.top().GetPtr()) + { + cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr(); + D3D::context->RSSetState(cur_raststate); + } + } + else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!"); +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.h index ff2423af79..f9c13a6583 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_GfxState.h @@ -1,142 +1,142 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include - -// VideoCommon -#include "VertexShaderGen.h" -#include "PixelShaderGen.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DBlob.h" - -namespace DX11 -{ - -namespace D3D -{ - -// stores the pipeline state to use when calling VertexManager::Flush() -class EmuGfxState -{ -public: - EmuGfxState(); - ~EmuGfxState(); - - void SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode); - void SetPShader(ID3D11PixelShader* shader); - void SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num); - void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv); - - void ApplyState(); // apply current state - void AlphaPass(); // only modify the current state to enable the alpha pass - void Reset(); - - // blend state - void SetAlphaBlendEnable(bool enable); - void SetRenderTargetWriteMask(UINT8 mask); - void SetSrcBlend(D3D11_BLEND val); - void SetDestBlend(D3D11_BLEND val); - void SetBlendOp(D3D11_BLEND_OP val); - - // sampler states - void SetSamplerFilter(DWORD stage, D3D11_FILTER filter); - - // TODO: add methods for changing the other states instead of modifying them directly - - D3D11_SAMPLER_DESC samplerdesc[8]; - D3D11_RASTERIZER_DESC rastdesc; - D3D11_DEPTH_STENCIL_DESC depthdesc; - - float psconstants[C_PENVCONST_END*4]; - float vsconstants[C_VENVCONST_END*4]; - bool vscbufchanged; - bool pscbufchanged; - -private: - ID3D11VertexShader* vertexshader; - D3DBlob* vsbytecode; - ID3D11PixelShader* pixelshader; - D3DBlob* psbytecode; - bool vshaderchanged; - - ID3D11Buffer* vscbuf; - ID3D11Buffer* pscbuf; - - ID3D11InputLayout* inp_layout; - D3D11_INPUT_ELEMENT_DESC inp_elems[32]; - int num_inp_elems; - - ID3D11ShaderResourceView* shader_resources[8]; - D3D11_BLEND_DESC blenddesc; - - bool apply_called; -}; - -template class AutoState -{ -public: - AutoState(const T* object); - AutoState(const AutoState &source); - ~AutoState(); - - const inline T* GetPtr() const { return state; } - -private: - const T* state; -}; - -typedef AutoState AutoBlendState; -typedef AutoState AutoDepthStencilState; -typedef AutoState AutoRasterizerState; - -class StateManager -{ -public: - StateManager(); - - // call any of these to change the affected states - void PushBlendState(const ID3D11BlendState* state); - void PushDepthState(const ID3D11DepthStencilState* state); - void PushRasterizerState(const ID3D11RasterizerState* state); - - // call these after drawing - void PopBlendState(); - void PopDepthState(); - void PopRasterizerState(); - - // call this before any drawing operation if states could have changed meanwhile - void Apply(); - -private: - std::stack blendstates; - std::stack depthstates; - std::stack raststates; - ID3D11BlendState* cur_blendstate; - ID3D11DepthStencilState* cur_depthstate; - ID3D11RasterizerState* cur_raststate; -}; - -extern EmuGfxState* gfxstate; -extern StateManager* stateman; - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include + +// VideoCommon +#include "VertexShaderGen.h" +#include "PixelShaderGen.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DBlob.h" + +namespace DX11 +{ + +namespace D3D +{ + +// stores the pipeline state to use when calling VertexManager::Flush() +class EmuGfxState +{ +public: + EmuGfxState(); + ~EmuGfxState(); + + void SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode); + void SetPShader(ID3D11PixelShader* shader); + void SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num); + void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv); + + void ApplyState(); // apply current state + void AlphaPass(); // only modify the current state to enable the alpha pass + void Reset(); + + // blend state + void SetAlphaBlendEnable(bool enable); + void SetRenderTargetWriteMask(UINT8 mask); + void SetSrcBlend(D3D11_BLEND val); + void SetDestBlend(D3D11_BLEND val); + void SetBlendOp(D3D11_BLEND_OP val); + + // sampler states + void SetSamplerFilter(DWORD stage, D3D11_FILTER filter); + + // TODO: add methods for changing the other states instead of modifying them directly + + D3D11_SAMPLER_DESC samplerdesc[8]; + D3D11_RASTERIZER_DESC rastdesc; + D3D11_DEPTH_STENCIL_DESC depthdesc; + + float psconstants[C_PENVCONST_END*4]; + float vsconstants[C_VENVCONST_END*4]; + bool vscbufchanged; + bool pscbufchanged; + +private: + ID3D11VertexShader* vertexshader; + D3DBlob* vsbytecode; + ID3D11PixelShader* pixelshader; + D3DBlob* psbytecode; + bool vshaderchanged; + + ID3D11Buffer* vscbuf; + ID3D11Buffer* pscbuf; + + ID3D11InputLayout* inp_layout; + D3D11_INPUT_ELEMENT_DESC inp_elems[32]; + int num_inp_elems; + + ID3D11ShaderResourceView* shader_resources[8]; + D3D11_BLEND_DESC blenddesc; + + bool apply_called; +}; + +template class AutoState +{ +public: + AutoState(const T* object); + AutoState(const AutoState &source); + ~AutoState(); + + const inline T* GetPtr() const { return state; } + +private: + const T* state; +}; + +typedef AutoState AutoBlendState; +typedef AutoState AutoDepthStencilState; +typedef AutoState AutoRasterizerState; + +class StateManager +{ +public: + StateManager(); + + // call any of these to change the affected states + void PushBlendState(const ID3D11BlendState* state); + void PushDepthState(const ID3D11DepthStencilState* state); + void PushRasterizerState(const ID3D11RasterizerState* state); + + // call these after drawing + void PopBlendState(); + void PopDepthState(); + void PopRasterizerState(); + + // call this before any drawing operation if states could have changed meanwhile + void Apply(); + +private: + std::stack blendstates; + std::stack depthstates; + std::stack raststates; + ID3D11BlendState* cur_blendstate; + ID3D11DepthStencilState* cur_depthstate; + ID3D11RasterizerState* cur_raststate; +}; + +extern EmuGfxState* gfxstate; +extern StateManager* stateman; + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_NativeVertexFormat.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_NativeVertexFormat.cpp index 2ac5afb219..dd7753e252 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_NativeVertexFormat.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_NativeVertexFormat.cpp @@ -1,150 +1,150 @@ - -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "MemoryUtil.h" -#include "x64Emitter.h" -#include "ABI.h" - -// VideoCommon -#include "Profiler.h" -#include "CPMemory.h" -#include "VertexShaderGen.h" -#include "NativeVertexFormat.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_VertexShaderCache.h" -#include "DX11_VertexManager.h" - -namespace DX11 -{ - -class D3DVertexFormat : public NativeVertexFormat -{ - D3D11_INPUT_ELEMENT_DESC m_elems[32]; - UINT m_num_elems; - -public: - D3DVertexFormat() : m_num_elems(0) {} - void Initialize(const PortableVertexDeclaration &_vtx_decl); - void SetupVertexPointers() const; -}; - -NativeVertexFormat* VertexManager::CreateNativeVertexFormat() -{ - return new D3DVertexFormat; -} - -DXGI_FORMAT VarToD3D(VarType t, int size) -{ - DXGI_FORMAT retval = DXGI_FORMAT_UNKNOWN; - static const DXGI_FORMAT lookup1[5] = { - DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R32_FLOAT - }; - static const DXGI_FORMAT lookup2[5] = { - DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R32G32_FLOAT - }; - static const DXGI_FORMAT lookup3[5] = { - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT - }; - static const DXGI_FORMAT lookup4[5] = { - DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R32G32B32A32_FLOAT - }; - - switch (size) - { - case 1: retval = lookup1[t]; break; - case 2: retval = lookup2[t]; break; - case 3: retval = lookup3[t]; break; - case 4: retval = lookup4[t]; break; - default: break; - } - if (retval == DXGI_FORMAT_UNKNOWN) - { - PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size); - } - return retval; -} - -void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) -{ - vertex_stride = _vtx_decl.stride; - memset(m_elems, 0, sizeof(m_elems)); - - m_elems[m_num_elems].SemanticName = "POSITION"; - m_elems[m_num_elems].AlignedByteOffset = 0; - m_elems[m_num_elems].Format = DXGI_FORMAT_R32G32B32_FLOAT; - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - - for (int i = 0; i < 3; i++) - { - if (_vtx_decl.normal_offset[i] > 0) - { - m_elems[m_num_elems].SemanticName = "NORMAL"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.normal_offset[i]; - m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } - - for (int i = 0; i < 2; i++) - { - if (_vtx_decl.color_offset[i] > 0) - { - m_elems[m_num_elems].SemanticName = "COLOR"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.color_offset[i]; - m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.color_gl_type, 4); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } - - for (int i = 0; i < 8; i++) - { - if (_vtx_decl.texcoord_offset[i] > 0) - { - m_elems[m_num_elems].SemanticName = "TEXCOORD"; - m_elems[m_num_elems].SemanticIndex = i; - m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.texcoord_offset[i]; - m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]); - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } - } - - if (_vtx_decl.posmtx_offset != -1) - { - m_elems[m_num_elems].SemanticName = "BLENDINDICES"; - m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.posmtx_offset; - m_elems[m_num_elems].Format = DXGI_FORMAT_R8G8B8A8_UNORM; - m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - ++m_num_elems; - } -} - -void D3DVertexFormat::SetupVertexPointers() const -{ - D3D::gfxstate->SetInputElements(m_elems, m_num_elems); -} - -} + +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "MemoryUtil.h" +#include "x64Emitter.h" +#include "ABI.h" + +// VideoCommon +#include "Profiler.h" +#include "CPMemory.h" +#include "VertexShaderGen.h" +#include "NativeVertexFormat.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_VertexShaderCache.h" +#include "DX11_VertexManager.h" + +namespace DX11 +{ + +class D3DVertexFormat : public NativeVertexFormat +{ + D3D11_INPUT_ELEMENT_DESC m_elems[32]; + UINT m_num_elems; + +public: + D3DVertexFormat() : m_num_elems(0) {} + void Initialize(const PortableVertexDeclaration &_vtx_decl); + void SetupVertexPointers() const; +}; + +NativeVertexFormat* VertexManager::CreateNativeVertexFormat() +{ + return new D3DVertexFormat; +} + +DXGI_FORMAT VarToD3D(VarType t, int size) +{ + DXGI_FORMAT retval = DXGI_FORMAT_UNKNOWN; + static const DXGI_FORMAT lookup1[5] = { + DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R32_FLOAT + }; + static const DXGI_FORMAT lookup2[5] = { + DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R32G32_FLOAT + }; + static const DXGI_FORMAT lookup3[5] = { + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT + }; + static const DXGI_FORMAT lookup4[5] = { + DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R32G32B32A32_FLOAT + }; + + switch (size) + { + case 1: retval = lookup1[t]; break; + case 2: retval = lookup2[t]; break; + case 3: retval = lookup3[t]; break; + case 4: retval = lookup4[t]; break; + default: break; + } + if (retval == DXGI_FORMAT_UNKNOWN) + { + PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size); + } + return retval; +} + +void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) +{ + vertex_stride = _vtx_decl.stride; + memset(m_elems, 0, sizeof(m_elems)); + + m_elems[m_num_elems].SemanticName = "POSITION"; + m_elems[m_num_elems].AlignedByteOffset = 0; + m_elems[m_num_elems].Format = DXGI_FORMAT_R32G32B32_FLOAT; + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + + for (int i = 0; i < 3; i++) + { + if (_vtx_decl.normal_offset[i] > 0) + { + m_elems[m_num_elems].SemanticName = "NORMAL"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.normal_offset[i]; + m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } + + for (int i = 0; i < 2; i++) + { + if (_vtx_decl.color_offset[i] > 0) + { + m_elems[m_num_elems].SemanticName = "COLOR"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.color_offset[i]; + m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.color_gl_type, 4); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } + + for (int i = 0; i < 8; i++) + { + if (_vtx_decl.texcoord_offset[i] > 0) + { + m_elems[m_num_elems].SemanticName = "TEXCOORD"; + m_elems[m_num_elems].SemanticIndex = i; + m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.texcoord_offset[i]; + m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]); + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } + } + + if (_vtx_decl.posmtx_offset != -1) + { + m_elems[m_num_elems].SemanticName = "BLENDINDICES"; + m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.posmtx_offset; + m_elems[m_num_elems].Format = DXGI_FORMAT_R8G8B8A8_UNORM; + m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ++m_num_elems; + } +} + +void D3DVertexFormat::SetupVertexPointers() const +{ + D3D::gfxstate->SetInputElements(m_elems, m_num_elems); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.cpp index a017600c1f..64a710dbf7 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.cpp @@ -1,306 +1,306 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "Common.h" -#include "FileUtil.h" -#include "LinearDiskCache.h" - -// VideoCommon -#include "Statistics.h" -#include "VideoConfig.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" -#include "ImageWrite.h" -#include "PixelShaderGen.h" -#include "PixelShaderManager.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DShader.h" -#include "DX11_PixelShaderCache.h" - -#include - -#include "../Main.h" - -namespace DX11 -{ - -PixelShaderCache::PSCache PixelShaderCache::PixelShaders; -const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry; - -LinearDiskCache g_ps_disk_cache; - -ID3D11PixelShader* s_ColorMatrixProgram = NULL; -ID3D11PixelShader* s_ColorCopyProgram = NULL; -ID3D11PixelShader* s_DepthMatrixProgram = NULL; -ID3D11PixelShader* s_ClearProgram = NULL; - -const char clear_program_code[] = { - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float4 incol0 : COLOR0){\n" - "ocol0 = incol0;\n" - "}\n" -}; - -const char color_copy_program_code[] = { - "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - "in float2 uv0 : TEXCOORD0){\n" - "ocol0 = Tex0.Sample(samp0,uv0);\n" - "}\n" -}; - -const char color_matrix_program_code[] = { - "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" - "uniform float4 cColMatrix[5] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - "in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" - "float4 texcol = Tex0.Sample(samp0,uv0);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; - -const char depth_matrix_program[] = { - "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" - "uniform float4 cColMatrix[5] : register(c0);\n" - "void main(\n" - "out float4 ocol0 : SV_Target,\n" - " in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" - "float4 texcol = Tex0.Sample(samp0,uv0);\n" - "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" - "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n" -}; - -ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram() -{ - return s_ColorMatrixProgram; -} - -ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram() -{ - return s_DepthMatrixProgram; -} - -ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram() -{ - return s_ColorCopyProgram; -} - -ID3D11PixelShader* PixelShaderCache::GetClearProgram() -{ - return s_ClearProgram; -} - -// HACK to avoid some invasive VideoCommon changes -// these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something -// offset given in floats, table index is float4 -unsigned int ps_constant_offset_table[] = { - 0, 4, 8, 12, // C_COLORS, 16 - 16, 20, 24, 28, // C_KCOLORS, 16 - 32, // C_ALPHA, 4 - 36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32 - 68, 72, // C_ZBIAS, 8 - 76, 80, // C_INDTEXSCALE, 8 - 84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24 - 108, 112, // C_FOG, 8 - 116, 120, 124 ,128, // C_COLORMATRIX, 16 - 132, 136, 140, 144, 148, // C_PLIGHTS0, 20 - 152, 156, 160, 164, 168, // C_PLIGHTS1, 20 - 172, 176, 180, 184, 188, // C_PLIGHTS2, 20 - 192, 196, 200, 204, 208, // C_PLIGHTS3, 20 - 212, 216, 220, 224, 228, // C_PLIGHTS4, 20 - 232, 236, 240, 244, 248, // C_PLIGHTS5, 20 - 252, 256, 260, 264, 268, // C_PLIGHTS6, 20 - 272, 276, 280, 284, 288, // C_PLIGHTS7, 20 - 292, 296, 300, 304, // C_PMATERIALS, 16 -}; -void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - D3D::gfxstate->psconstants[ps_constant_offset_table[const_number] ] = f1; - D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+1] = f2; - D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+2] = f3; - D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+3] = f4; - D3D::gfxstate->pscbufchanged = true; -} - -void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float* f) -{ - memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4); - D3D::gfxstate->pscbufchanged = true; -} - -void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f) -{ - memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count); - D3D::gfxstate->pscbufchanged = true; -} - -// this class will load the precompiled shaders into our cache -class PixelShaderCacheInserter : public LinearDiskCacheReader -{ -public: - void Read(const u8* key, int key_size, const u8* value, int value_size) - { - PIXELSHADERUID uid; - if (key_size != sizeof(uid)) { - ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache"); - return; - } - memcpy(&uid, key, key_size); - PixelShaderCache::InsertByteCode(uid, (void*)value, value_size); - } -}; - -PixelShaderCache::PixelShaderCache() -{ - // used when drawing clear quads - s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code, sizeof(clear_program_code)); - CHECK(s_ClearProgram!=NULL, "Create clear pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader"); - - // used when copying/resolving the color buffer - s_ColorCopyProgram = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code)); - CHECK(s_ColorCopyProgram!=NULL, "Create color copy pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color copy pixel shader"); - - // used for color conversion - s_ColorMatrixProgram = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code)); - CHECK(s_ColorMatrixProgram!=NULL, "Create color matrix pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color matrix pixel shader"); - - // used for depth copy - s_DepthMatrixProgram = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program)); - CHECK(s_DepthMatrixProgram!=NULL, "Create depth matrix pixel shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "depth matrix pixel shader"); - - Clear(); - - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - char cache_filename[MAX_PATH]; - sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); - PixelShaderCacheInserter inserter; - g_ps_disk_cache.OpenAndRead(cache_filename, &inserter); -} - -// ONLY to be used during shutdown. -void PixelShaderCache::Clear() -{ - for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++) - iter->second.Destroy(); - PixelShaders.clear(); -} - -PixelShaderCache::~PixelShaderCache() -{ - SAFE_RELEASE(s_ColorMatrixProgram); - SAFE_RELEASE(s_ColorCopyProgram); - SAFE_RELEASE(s_DepthMatrixProgram); - SAFE_RELEASE(s_ClearProgram); - - Clear(); - g_ps_disk_cache.Sync(); - g_ps_disk_cache.Close(); -} - -bool PixelShaderCache::SetShader(bool dstAlpha) -{ - PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlpha); - - // check if the shader is already set - if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) - { - PSCache::const_iterator iter = PixelShaders.find(uid); - return (iter != PixelShaders.end() && iter->second.shader); - } - - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); - - // check if the shader is already in the cache - PSCache::iterator iter = PixelShaders.find(uid); - if (iter != PixelShaders.end()) - { - iter->second.frameCount = frameCount; - const PSCacheEntry &entry = iter->second; - last_entry = &entry; - - D3D::gfxstate->SetPShader(entry.shader); - return (entry.shader != NULL); - } - - // need to compile a new shader - const char* code = GeneratePixelShaderCode(dstAlpha, API_D3D11); - - D3DBlob* pbytecode; - if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode)) - { - PanicAlert("Failed to compile Pixel Shader:\n\n%s", code); - return false; - } - - // insert the bytecode into the caches - g_ps_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size()); - g_ps_disk_cache.Sync(); - - bool result = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); - D3D::gfxstate->SetPShader(last_entry->shader); - pbytecode->Release(); - return result; -} - -bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen) -{ - ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); - if (shader == NULL) - { - PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__, __LINE__); - return false; - } - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); - - // make an entry in the table - PSCacheEntry newentry; - newentry.shader = shader; - newentry.frameCount = frameCount; - PixelShaders[uid] = newentry; - last_entry = &PixelShaders[uid]; - - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); - - return true; -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "Common.h" +#include "FileUtil.h" +#include "LinearDiskCache.h" + +// VideoCommon +#include "Statistics.h" +#include "VideoConfig.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" +#include "ImageWrite.h" +#include "PixelShaderGen.h" +#include "PixelShaderManager.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DShader.h" +#include "DX11_PixelShaderCache.h" + +#include + +#include "../Main.h" + +namespace DX11 +{ + +PixelShaderCache::PSCache PixelShaderCache::PixelShaders; +const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry; + +LinearDiskCache g_ps_disk_cache; + +ID3D11PixelShader* s_ColorMatrixProgram = NULL; +ID3D11PixelShader* s_ColorCopyProgram = NULL; +ID3D11PixelShader* s_DepthMatrixProgram = NULL; +ID3D11PixelShader* s_ClearProgram = NULL; + +const char clear_program_code[] = { + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float4 incol0 : COLOR0){\n" + "ocol0 = incol0;\n" + "}\n" +}; + +const char color_copy_program_code[] = { + "sampler samp0 : register(s0);\n" + "Texture2D Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float2 uv0 : TEXCOORD0){\n" + "ocol0 = Tex0.Sample(samp0,uv0);\n" + "}\n" +}; + +const char color_matrix_program_code[] = { + "sampler samp0 : register(s0);\n" + "Texture2D Tex0 : register(t0);\n" + "uniform float4 cColMatrix[5] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + " in float2 uv0 : TEXCOORD0){\n" + "float4 texcol = Tex0.Sample(samp0,uv0);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n" +}; + +const char depth_matrix_program[] = { + "sampler samp0 : register(s0);\n" + "Texture2D Tex0 : register(t0);\n" + "uniform float4 cColMatrix[5] : register(c0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + " in float4 pos : SV_Position,\n" + " in float2 uv0 : TEXCOORD0){\n" + "float4 texcol = Tex0.Sample(samp0,uv0);\n" + "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" + "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n" +}; + +ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram() +{ + return s_ColorMatrixProgram; +} + +ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram() +{ + return s_DepthMatrixProgram; +} + +ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram() +{ + return s_ColorCopyProgram; +} + +ID3D11PixelShader* PixelShaderCache::GetClearProgram() +{ + return s_ClearProgram; +} + +// HACK to avoid some invasive VideoCommon changes +// these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something +// offset given in floats, table index is float4 +unsigned int ps_constant_offset_table[] = { + 0, 4, 8, 12, // C_COLORS, 16 + 16, 20, 24, 28, // C_KCOLORS, 16 + 32, // C_ALPHA, 4 + 36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32 + 68, 72, // C_ZBIAS, 8 + 76, 80, // C_INDTEXSCALE, 8 + 84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24 + 108, 112, // C_FOG, 8 + 116, 120, 124 ,128, // C_COLORMATRIX, 16 + 132, 136, 140, 144, 148, // C_PLIGHTS0, 20 + 152, 156, 160, 164, 168, // C_PLIGHTS1, 20 + 172, 176, 180, 184, 188, // C_PLIGHTS2, 20 + 192, 196, 200, 204, 208, // C_PLIGHTS3, 20 + 212, 216, 220, 224, 228, // C_PLIGHTS4, 20 + 232, 236, 240, 244, 248, // C_PLIGHTS5, 20 + 252, 256, 260, 264, 268, // C_PLIGHTS6, 20 + 272, 276, 280, 284, 288, // C_PLIGHTS7, 20 + 292, 296, 300, 304, // C_PMATERIALS, 16 +}; +void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + D3D::gfxstate->psconstants[ps_constant_offset_table[const_number] ] = f1; + D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+1] = f2; + D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+2] = f3; + D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+3] = f4; + D3D::gfxstate->pscbufchanged = true; +} + +void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float* f) +{ + memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4); + D3D::gfxstate->pscbufchanged = true; +} + +void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f) +{ + memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count); + D3D::gfxstate->pscbufchanged = true; +} + +// this class will load the precompiled shaders into our cache +class PixelShaderCacheInserter : public LinearDiskCacheReader +{ +public: + void Read(const u8* key, int key_size, const u8* value, int value_size) + { + PIXELSHADERUID uid; + if (key_size != sizeof(uid)) { + ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache"); + return; + } + memcpy(&uid, key, key_size); + PixelShaderCache::InsertByteCode(uid, (void*)value, value_size); + } +}; + +PixelShaderCache::PixelShaderCache() +{ + // used when drawing clear quads + s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code, sizeof(clear_program_code)); + CHECK(s_ClearProgram!=NULL, "Create clear pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader"); + + // used when copying/resolving the color buffer + s_ColorCopyProgram = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code)); + CHECK(s_ColorCopyProgram!=NULL, "Create color copy pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color copy pixel shader"); + + // used for color conversion + s_ColorMatrixProgram = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code)); + CHECK(s_ColorMatrixProgram!=NULL, "Create color matrix pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color matrix pixel shader"); + + // used for depth copy + s_DepthMatrixProgram = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program)); + CHECK(s_DepthMatrixProgram!=NULL, "Create depth matrix pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "depth matrix pixel shader"); + + Clear(); + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + char cache_filename[MAX_PATH]; + sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); + PixelShaderCacheInserter inserter; + g_ps_disk_cache.OpenAndRead(cache_filename, &inserter); +} + +// ONLY to be used during shutdown. +void PixelShaderCache::Clear() +{ + for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++) + iter->second.Destroy(); + PixelShaders.clear(); +} + +PixelShaderCache::~PixelShaderCache() +{ + SAFE_RELEASE(s_ColorMatrixProgram); + SAFE_RELEASE(s_ColorCopyProgram); + SAFE_RELEASE(s_DepthMatrixProgram); + SAFE_RELEASE(s_ClearProgram); + + Clear(); + g_ps_disk_cache.Sync(); + g_ps_disk_cache.Close(); +} + +bool PixelShaderCache::SetShader(bool dstAlpha) +{ + PIXELSHADERUID uid; + GetPixelShaderId(&uid, dstAlpha); + + // check if the shader is already set + if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) + { + PSCache::const_iterator iter = PixelShaders.find(uid); + return (iter != PixelShaders.end() && iter->second.shader); + } + + memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + + // check if the shader is already in the cache + PSCache::iterator iter = PixelShaders.find(uid); + if (iter != PixelShaders.end()) + { + iter->second.frameCount = frameCount; + const PSCacheEntry &entry = iter->second; + last_entry = &entry; + + D3D::gfxstate->SetPShader(entry.shader); + return (entry.shader != NULL); + } + + // need to compile a new shader + const char* code = GeneratePixelShaderCode(dstAlpha, API_D3D11); + + D3DBlob* pbytecode; + if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode)) + { + PanicAlert("Failed to compile Pixel Shader:\n\n%s", code); + return false; + } + + // insert the bytecode into the caches + g_ps_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size()); + g_ps_disk_cache.Sync(); + + bool result = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + D3D::gfxstate->SetPShader(last_entry->shader); + pbytecode->Release(); + return result; +} + +bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen) +{ + ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); + if (shader == NULL) + { + PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__, __LINE__); + return false; + } + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache"); + + // make an entry in the table + PSCacheEntry newentry; + newentry.shader = shader; + newentry.frameCount = frameCount; + PixelShaders[uid] = newentry; + last_entry = &PixelShaders[uid]; + + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, PixelShaders.size()); + + return true; +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.h index 05f7ea12ca..6735d4d30a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_PixelShaderCache.h @@ -1,74 +1,74 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include - -// Common -#include "Common.h" -#include "LinearDiskCache.h" - -// VideoCommon -#include "PixelShaderGen.h" -#include "VertexShaderGen.h" - -// DX11 -#include "DX11_D3DBase.h" - -#include "../PixelShaderCache.h" - -namespace DX11 -{ - -class PixelShaderCache : public ::PixelShaderCacheBase -{ -public: - PixelShaderCache(); - ~PixelShaderCache(); - - void Clear(); - - bool SetShader(bool dstAlpha); - static bool InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen); - - static ID3D11PixelShader* GetColorMatrixProgram(); - static ID3D11PixelShader* GetColorCopyProgram(); - static ID3D11PixelShader* GetDepthMatrixProgram(); - static ID3D11PixelShader* GetClearProgram(); - - void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetPSConstant4fv(unsigned int const_number, const float *f); - void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f); - -private: - struct PSCacheEntry - { - ID3D11PixelShader* shader; - int frameCount; - - PSCacheEntry() : shader(NULL), frameCount(0) {} - void Destroy() { SAFE_RELEASE(shader); } - }; - - typedef std::map PSCache; - - static PSCache PixelShaders; - static const PSCacheEntry* last_entry; -}; - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include + +// Common +#include "Common.h" +#include "LinearDiskCache.h" + +// VideoCommon +#include "PixelShaderGen.h" +#include "VertexShaderGen.h" + +// DX11 +#include "DX11_D3DBase.h" + +#include "../PixelShaderCache.h" + +namespace DX11 +{ + +class PixelShaderCache : public ::PixelShaderCacheBase +{ +public: + PixelShaderCache(); + ~PixelShaderCache(); + + void Clear(); + + bool SetShader(bool dstAlpha); + static bool InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen); + + static ID3D11PixelShader* GetColorMatrixProgram(); + static ID3D11PixelShader* GetColorCopyProgram(); + static ID3D11PixelShader* GetDepthMatrixProgram(); + static ID3D11PixelShader* GetClearProgram(); + + void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetPSConstant4fv(unsigned int const_number, const float *f); + void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f); + +private: + struct PSCacheEntry + { + ID3D11PixelShader* shader; + int frameCount; + + PSCacheEntry() : shader(NULL), frameCount(0) {} + void Destroy() { SAFE_RELEASE(shader); } + }; + + typedef std::map PSCache; + + static PSCache PixelShaders; + static const PSCacheEntry* last_entry; +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_Render.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_Render.h index a0af4f4a20..632dc73932 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_Render.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_Render.h @@ -1,52 +1,52 @@ - -#pragma once - -#include "MathUtil.h" - -#include "VideoCommon.h" -#include "Renderer.h" -#include "pluginspecs_video.h" - -namespace DX11 -{ - -class Renderer : public ::RendererBase -{ -public: - Renderer(); - ~Renderer(); - - // What's the real difference between these? Too similar names. - void ResetAPIState(); - void RestoreAPIState(); - - static void SetupDeviceObjects(); - static void TeardownDeviceObjects(); - - void SetColorMask(); - void SetBlendMode(bool forceUpdate); - bool SetScissorRect(); - - void SetGenerationMode(); - void SetDepthMode(); - void SetLogicOpMode(); - void SetSamplerState(int stage,int texindex); - - u32 AccessEFB(EFBAccessType type, int x, int y); - - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); - void UpdateViewport(); - - // virtual funcs used by RendererBase::Swap - void PrepareXFBCopy(const TargetRectangle &dst_rect); - void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); - void EndFrame(); - void Present(); - bool CheckForResize(); - void GetBackBufferSize(int* w, int* h); - void RecreateFramebufferManger(); - void BeginFrame(); -}; - -} + +#pragma once + +#include "MathUtil.h" + +#include "VideoCommon.h" +#include "Renderer.h" +#include "pluginspecs_video.h" + +namespace DX11 +{ + +class Renderer : public ::RendererBase +{ +public: + Renderer(); + ~Renderer(); + + // What's the real difference between these? Too similar names. + void ResetAPIState(); + void RestoreAPIState(); + + static void SetupDeviceObjects(); + static void TeardownDeviceObjects(); + + void SetColorMask(); + void SetBlendMode(bool forceUpdate); + bool SetScissorRect(); + + void SetGenerationMode(); + void SetDepthMode(); + void SetLogicOpMode(); + void SetSamplerState(int stage,int texindex); + + u32 AccessEFB(EFBAccessType type, int x, int y); + + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); + void UpdateViewport(); + + // virtual funcs used by RendererBase::Swap + void PrepareXFBCopy(const TargetRectangle &dst_rect); + void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); + void EndFrame(); + void Present(); + bool CheckForResize(); + void GetBackBufferSize(int* w, int* h); + void RecreateFramebufferManger(); + void BeginFrame(); +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.cpp index 38b4a4c55f..109d4ae957 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.cpp @@ -1,230 +1,230 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -// Common -#include "CommonPaths.h" -#include "FileUtil.h" -#include "MemoryUtil.h" -#include "Hash.h" - -// VideoCommon -#include "VideoConfig.h" -#include "Statistics.h" -#include "PixelShaderManager.h" -#include "VertexShaderManager.h" -#include "TextureDecoder.h" -#include "HiresTextures.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DTexture.h" -#include "DX11_D3DUtil.h" -#include "DX11_FramebufferManager.h" -#include "DX11_PixelShaderCache.h" -#include "DX11_VertexShaderCache.h" -#include "DX11_TextureCache.h" - -#include "../Main.h" - -namespace DX11 -{ - -ID3D11BlendState* efbcopyblendstate = NULL; -ID3D11RasterizerState* efbcopyraststate = NULL; -ID3D11DepthStencilState* efbcopydepthstate = NULL; -ID3D11Buffer* efbcopycbuf[20] = {}; - -TextureCache::TCacheEntry::~TCacheEntry() -{ - SAFE_RELEASE(texture); -} - -void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) -{ - D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage); -} - -void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) -{ - // stretch picture with increased internal resolution - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)Scaledw, (float)Scaledh); - D3D::context->RSSetViewports(1, &vp); - - // set transformation - if (NULL == efbcopycbuf[cbufid]) - { - const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); - D3D11_SUBRESOURCE_DATA data; - data.pSysMem = colmat; - HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]); - CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); - } - D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]); - - const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect); - // TODO: try targetSource.asRECT(); - const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); - - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (bScaleByHalf) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); - - D3D::stateman->PushBlendState(efbcopyblendstate); - D3D::stateman->PushRasterizerState(efbcopyraststate); - D3D::stateman->PushDepthState(efbcopydepthstate); - - D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL); - - D3D::drawShadedTexQuad( - (bFromZBuffer) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(), - &sourcerect, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(), - (bFromZBuffer) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - - D3D::stateman->PopBlendState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopRasterizerState(); -} - -void TextureCache::TCacheEntry::Bind(unsigned int stage) -{ - D3D::gfxstate->SetShaderResource(stage, texture->GetSRV()); -} - -TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, - unsigned int height, unsigned int expanded_width, - unsigned int tex_levels, PC_TexFormat pcfmt) -{ - D3D11_SUBRESOURCE_DATA srdata; - - D3D11_SUBRESOURCE_DATA *data = NULL; - D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0; - D3D11_USAGE usage = D3D11_USAGE_DEFAULT; - - // TODO: temp - tex_levels = 1; - - if (1 == tex_levels) - { - cpu_access = D3D11_CPU_ACCESS_WRITE; - usage = D3D11_USAGE_DYNAMIC; - - srdata.pSysMem = temp; - srdata.SysMemPitch = 4 * expanded_width; - data = &srdata; - } - - const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, - width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access); - - ID3D11Texture2D *pTexture; - HRESULT hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture); - CHECK(SUCCEEDED(hr), "Create texture of the TextureCache"); - - TCacheEntry* const entry = new TCacheEntry(new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE)); - entry->usage = usage; - - // TODO: silly debug names - D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache"); - - // wuts this? - //if (0 == tex_levels) - // PD3DX11FilterTexture(D3D::context, entry->texture->GetTex(), 0, D3DX11_DEFAULT); - - // TODO: this good? - //if (1 != tex_levels) - // entry->Load(width, height, expanded_width, 0); - - SAFE_RELEASE(pTexture); - - return entry; -} - -TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) -{ - return new TCacheEntry(D3DTexture2D::Create(scaled_tex_w, scaled_tex_h, - (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM)); -} - -TextureCache::TextureCache() -{ - HRESULT hr; - - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = FALSE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &efbcopyblendstate); - CHECK(hr==S_OK, "Create blend state for CopyRenderTargetToTexture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyblendstate, "blend state used in CopyRenderTargetToTexture"); - - D3D11_DEPTH_STENCIL_DESC depthdesc; - depthdesc.DepthEnable = FALSE; - depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthdesc.DepthFunc = D3D11_COMPARISON_LESS; - depthdesc.StencilEnable = FALSE; - depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - hr = D3D::device->CreateDepthStencilState(&depthdesc, &efbcopydepthstate); - CHECK(hr==S_OK, "Create depth state for CopyRenderTargetToTexture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopydepthstate, "depth stencil state used in CopyRenderTargetToTexture"); - - D3D11_RASTERIZER_DESC rastdesc; - rastdesc.CullMode = D3D11_CULL_NONE; - rastdesc.FillMode = D3D11_FILL_SOLID; - rastdesc.FrontCounterClockwise = false; - rastdesc.DepthBias = false; - rastdesc.DepthBiasClamp = 0; - rastdesc.SlopeScaledDepthBias = 0; - rastdesc.DepthClipEnable = false; - rastdesc.ScissorEnable = false; - rastdesc.MultisampleEnable = false; - rastdesc.AntialiasedLineEnable = false; - hr = D3D::device->CreateRasterizerState(&rastdesc, &efbcopyraststate); - CHECK(hr==S_OK, "Create rasterizer state for CopyRenderTargetToTexture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyraststate, "rasterizer state used in CopyRenderTargetToTexture"); -} - -TextureCache::~TextureCache() -{ - SAFE_RELEASE(efbcopyblendstate); - SAFE_RELEASE(efbcopyraststate); - SAFE_RELEASE(efbcopydepthstate); - - for (unsigned int k = 0; k < 20; ++k) - SAFE_RELEASE(efbcopycbuf[k]); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +// Common +#include "CommonPaths.h" +#include "FileUtil.h" +#include "MemoryUtil.h" +#include "Hash.h" + +// VideoCommon +#include "VideoConfig.h" +#include "Statistics.h" +#include "PixelShaderManager.h" +#include "VertexShaderManager.h" +#include "TextureDecoder.h" +#include "HiresTextures.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DTexture.h" +#include "DX11_D3DUtil.h" +#include "DX11_FramebufferManager.h" +#include "DX11_PixelShaderCache.h" +#include "DX11_VertexShaderCache.h" +#include "DX11_TextureCache.h" + +#include "../Main.h" + +namespace DX11 +{ + +ID3D11BlendState* efbcopyblendstate = NULL; +ID3D11RasterizerState* efbcopyraststate = NULL; +ID3D11DepthStencilState* efbcopydepthstate = NULL; +ID3D11Buffer* efbcopycbuf[20] = {}; + +TextureCache::TCacheEntry::~TCacheEntry() +{ + SAFE_RELEASE(texture); +} + +void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level) +{ + D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage); +} + +void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) +{ + // stretch picture with increased internal resolution + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)Scaledw, (float)Scaledh); + D3D::context->RSSetViewports(1, &vp); + + // set transformation + if (NULL == efbcopycbuf[cbufid]) + { + const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = colmat; + HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]); + CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid); + D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); + } + D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]); + + const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect); + // TODO: try targetSource.asRECT(); + const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); + + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (bScaleByHalf) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); + + D3D::stateman->PushBlendState(efbcopyblendstate); + D3D::stateman->PushRasterizerState(efbcopyraststate); + D3D::stateman->PushDepthState(efbcopydepthstate); + + D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL); + + D3D::drawShadedTexQuad( + (bFromZBuffer) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(), + &sourcerect, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(), + (bFromZBuffer) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + + D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopRasterizerState(); +} + +void TextureCache::TCacheEntry::Bind(unsigned int stage) +{ + D3D::gfxstate->SetShaderResource(stage, texture->GetSRV()); +} + +TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, + unsigned int height, unsigned int expanded_width, + unsigned int tex_levels, PC_TexFormat pcfmt) +{ + D3D11_SUBRESOURCE_DATA srdata; + + D3D11_SUBRESOURCE_DATA *data = NULL; + D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0; + D3D11_USAGE usage = D3D11_USAGE_DEFAULT; + + // TODO: temp + tex_levels = 1; + + if (1 == tex_levels) + { + cpu_access = D3D11_CPU_ACCESS_WRITE; + usage = D3D11_USAGE_DYNAMIC; + + srdata.pSysMem = temp; + srdata.SysMemPitch = 4 * expanded_width; + data = &srdata; + } + + const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, + width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access); + + ID3D11Texture2D *pTexture; + HRESULT hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture); + CHECK(SUCCEEDED(hr), "Create texture of the TextureCache"); + + TCacheEntry* const entry = new TCacheEntry(new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE)); + entry->usage = usage; + + // TODO: silly debug names + D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache"); + + // wuts this? + //if (0 == tex_levels) + // PD3DX11FilterTexture(D3D::context, entry->texture->GetTex(), 0, D3DX11_DEFAULT); + + // TODO: this good? + //if (1 != tex_levels) + // entry->Load(width, height, expanded_width, 0); + + SAFE_RELEASE(pTexture); + + return entry; +} + +TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) +{ + return new TCacheEntry(D3DTexture2D::Create(scaled_tex_w, scaled_tex_h, + (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE), + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM)); +} + +TextureCache::TextureCache() +{ + HRESULT hr; + + D3D11_BLEND_DESC blenddesc; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = FALSE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + hr = D3D::device->CreateBlendState(&blenddesc, &efbcopyblendstate); + CHECK(hr==S_OK, "Create blend state for CopyRenderTargetToTexture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyblendstate, "blend state used in CopyRenderTargetToTexture"); + + D3D11_DEPTH_STENCIL_DESC depthdesc; + depthdesc.DepthEnable = FALSE; + depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthdesc.DepthFunc = D3D11_COMPARISON_LESS; + depthdesc.StencilEnable = FALSE; + depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + hr = D3D::device->CreateDepthStencilState(&depthdesc, &efbcopydepthstate); + CHECK(hr==S_OK, "Create depth state for CopyRenderTargetToTexture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopydepthstate, "depth stencil state used in CopyRenderTargetToTexture"); + + D3D11_RASTERIZER_DESC rastdesc; + rastdesc.CullMode = D3D11_CULL_NONE; + rastdesc.FillMode = D3D11_FILL_SOLID; + rastdesc.FrontCounterClockwise = false; + rastdesc.DepthBias = false; + rastdesc.DepthBiasClamp = 0; + rastdesc.SlopeScaledDepthBias = 0; + rastdesc.DepthClipEnable = false; + rastdesc.ScissorEnable = false; + rastdesc.MultisampleEnable = false; + rastdesc.AntialiasedLineEnable = false; + hr = D3D::device->CreateRasterizerState(&rastdesc, &efbcopyraststate); + CHECK(hr==S_OK, "Create rasterizer state for CopyRenderTargetToTexture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyraststate, "rasterizer state used in CopyRenderTargetToTexture"); +} + +TextureCache::~TextureCache() +{ + SAFE_RELEASE(efbcopyblendstate); + SAFE_RELEASE(efbcopyraststate); + SAFE_RELEASE(efbcopydepthstate); + + for (unsigned int k = 0; k < 20; ++k) + SAFE_RELEASE(efbcopycbuf[k]); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.h index 39433b7994..e98ee74860 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_TextureCache.h @@ -1,66 +1,66 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -// VideoCommon -#include "VideoCommon.h" -#include "BPMemory.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DTexture.h" - -#include "../TextureCache.h" - -namespace DX11 -{ - -class TextureCache : public ::TextureCacheBase -{ -public: - struct TCacheEntry : TCacheEntryBase - { - D3DTexture2D* texture; - - D3D11_USAGE usage; - - TCacheEntry(D3DTexture2D* _texture) : texture(_texture) {} - ~TCacheEntry(); - - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level); - - void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); - - void Bind(unsigned int stage); - }; - - TextureCache(); - ~TextureCache(); - - TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); - - TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); - - void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source_rect); - -}; - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +// VideoCommon +#include "VideoCommon.h" +#include "BPMemory.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DTexture.h" + +#include "../TextureCache.h" + +namespace DX11 +{ + +class TextureCache : public ::TextureCacheBase +{ +public: + struct TCacheEntry : TCacheEntryBase + { + D3DTexture2D* texture; + + D3D11_USAGE usage; + + TCacheEntry(D3DTexture2D* _texture) : texture(_texture) {} + ~TCacheEntry(); + + void Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level); + + void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); + + void Bind(unsigned int stage); + }; + + TextureCache(); + ~TextureCache(); + + TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); + + TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); + + void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source_rect); + +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.cpp index 2ad74f124f..dd57e75164 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.cpp @@ -1,194 +1,194 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -// Common -#include "Common.h" -#include "FileUtil.h" - -// VideoCommon -#include "BPStructs.h" -#include "XFStructs.h" -#include "Fifo.h" -#include "Statistics.h" -#include "Profiler.h" -#include "OpcodeDecoding.h" -#include "IndexGenerator.h" -#include "VertexShaderManager.h" -#include "PixelShaderManager.h" -#include "NativeVertexFormat.h" -#include "NativeVertexWriter.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DShader.h" -#include "DX11_D3DUtil.h" -#include "DX11_VertexManager.h" -#include "DX11_VertexShaderCache.h" -#include "DX11_PixelShaderCache.h" -#include "DX11_TextureCache.h" -#include "DX11_FramebufferManager.h" -#include "DX11_Render.h" - -#include "../Main.h" - -//using std::string; - -namespace DX11 -{ - -using namespace D3D; - -ID3D11Buffer* indexbuffers[NUM_INDEXBUFFERS] = {}; -ID3D11Buffer* vertexbuffers[NUM_VERTEXBUFFERS] = {}; - -// TODO: these seem ugly -inline ID3D11Buffer* GetSuitableIndexBuffer(const u32 minsize) -{ - for (u32 k = 0; k < NUM_INDEXBUFFERS - 1; ++k) - if (minsize > (((u32)MAXIBUFFERSIZE) >> k)) - return indexbuffers[k]; - return indexbuffers[NUM_INDEXBUFFERS - 1]; -} - -inline ID3D11Buffer* GetSuitableVertexBuffer(const u32 minsize) -{ - for (u32 k = 0; k < NUM_VERTEXBUFFERS - 1; ++k) - if (minsize > (((u32)MAXVBUFFERSIZE) >> (k + 1))) - return vertexbuffers[k]; - return vertexbuffers[NUM_VERTEXBUFFERS - 1]; -} - -void CreateDeviceObjects() -{ - D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAXIBUFFERSIZE * 2, - D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1) - { - CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, indexbuffers + k)), - "Failed to create index buffer [%i].", k); - D3D::SetDebugObjectName((ID3D11DeviceChild*)indexbuffers[k], "an index buffer of VertexManager"); - } - - bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufdesc.ByteWidth = MAXVBUFFERSIZE; - for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1) - { - CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, vertexbuffers + k)), - "Failed to create vertex buffer [%i].", k); - D3D::SetDebugObjectName((ID3D11DeviceChild*)vertexbuffers[k], "a vertex buffer of VertexManager"); - } -} - -void DestroyDeviceObjects() -{ - for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k) - SAFE_RELEASE(indexbuffers[k]); - - for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k) - SAFE_RELEASE(vertexbuffers[k]); -} - -VertexManager::VertexManager() -{ - CreateDeviceObjects(); -} - -VertexManager::~VertexManager() -{ - DestroyDeviceObjects(); - ResetBuffer(); -} - -void VertexManager::Draw(u32 stride, bool alphapass) -{ - static const UINT bufoffset = 0; - const UINT bufstride = stride; - - D3D11_MAPPED_SUBRESOURCE map; - ID3D11Buffer* const vertexbuffer = GetSuitableVertexBuffer((u32)(s_pCurBufferPointer - LocalVBuffer)); - - if (alphapass) - { - gfxstate->AlphaPass(); - } - else - { - context->Map(vertexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, LocalVBuffer, (u32)(s_pCurBufferPointer - LocalVBuffer)); - context->Unmap(vertexbuffer, 0); - - gfxstate->ApplyState(); - } - - D3D::context->IASetVertexBuffers(0, 1, &vertexbuffer, &bufstride, &bufoffset); - - if (IndexGenerator::GetNumTriangles() > 0) - { - u32 indexbuffersize = IndexGenerator::GetTriangleindexLen(); - ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); - if (!alphapass) - { - D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, TIBuffer, 2*indexbuffersize); - D3D::context->Unmap(indexbuffer, 0); - } - - D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); - - D3D::context->DrawIndexed(indexbuffersize, 0, 0); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumLines() > 0) - { - u32 indexbuffersize = IndexGenerator::GetLineindexLen(); - ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); - if (!alphapass) - { - D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, LIBuffer, 2*indexbuffersize); - D3D::context->Unmap(indexbuffer, 0); - } - - D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); - - D3D::context->DrawIndexed(indexbuffersize, 0, 0); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumPoints() > 0) - { - u32 indexbuffersize = IndexGenerator::GetPointindexLen(); - ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); - if (!alphapass) - { - D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, PIBuffer, 2*indexbuffersize); - D3D::context->Unmap(indexbuffer, 0); - } - - D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); - - D3D::context->DrawIndexed(indexbuffersize, 0, 0); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +// Common +#include "Common.h" +#include "FileUtil.h" + +// VideoCommon +#include "BPStructs.h" +#include "XFStructs.h" +#include "Fifo.h" +#include "Statistics.h" +#include "Profiler.h" +#include "OpcodeDecoding.h" +#include "IndexGenerator.h" +#include "VertexShaderManager.h" +#include "PixelShaderManager.h" +#include "NativeVertexFormat.h" +#include "NativeVertexWriter.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DShader.h" +#include "DX11_D3DUtil.h" +#include "DX11_VertexManager.h" +#include "DX11_VertexShaderCache.h" +#include "DX11_PixelShaderCache.h" +#include "DX11_TextureCache.h" +#include "DX11_FramebufferManager.h" +#include "DX11_Render.h" + +#include "../Main.h" + +//using std::string; + +namespace DX11 +{ + +using namespace D3D; + +ID3D11Buffer* indexbuffers[NUM_INDEXBUFFERS] = {}; +ID3D11Buffer* vertexbuffers[NUM_VERTEXBUFFERS] = {}; + +// TODO: these seem ugly +inline ID3D11Buffer* GetSuitableIndexBuffer(const u32 minsize) +{ + for (u32 k = 0; k < NUM_INDEXBUFFERS - 1; ++k) + if (minsize > (((u32)MAXIBUFFERSIZE) >> k)) + return indexbuffers[k]; + return indexbuffers[NUM_INDEXBUFFERS - 1]; +} + +inline ID3D11Buffer* GetSuitableVertexBuffer(const u32 minsize) +{ + for (u32 k = 0; k < NUM_VERTEXBUFFERS - 1; ++k) + if (minsize > (((u32)MAXVBUFFERSIZE) >> (k + 1))) + return vertexbuffers[k]; + return vertexbuffers[NUM_VERTEXBUFFERS - 1]; +} + +void CreateDeviceObjects() +{ + D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAXIBUFFERSIZE * 2, + D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1) + { + CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, indexbuffers + k)), + "Failed to create index buffer [%i].", k); + D3D::SetDebugObjectName((ID3D11DeviceChild*)indexbuffers[k], "an index buffer of VertexManager"); + } + + bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufdesc.ByteWidth = MAXVBUFFERSIZE; + for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1) + { + CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, vertexbuffers + k)), + "Failed to create vertex buffer [%i].", k); + D3D::SetDebugObjectName((ID3D11DeviceChild*)vertexbuffers[k], "a vertex buffer of VertexManager"); + } +} + +void DestroyDeviceObjects() +{ + for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k) + SAFE_RELEASE(indexbuffers[k]); + + for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k) + SAFE_RELEASE(vertexbuffers[k]); +} + +VertexManager::VertexManager() +{ + CreateDeviceObjects(); +} + +VertexManager::~VertexManager() +{ + DestroyDeviceObjects(); + ResetBuffer(); +} + +void VertexManager::Draw(u32 stride, bool alphapass) +{ + static const UINT bufoffset = 0; + const UINT bufstride = stride; + + D3D11_MAPPED_SUBRESOURCE map; + ID3D11Buffer* const vertexbuffer = GetSuitableVertexBuffer((u32)(s_pCurBufferPointer - LocalVBuffer)); + + if (alphapass) + { + gfxstate->AlphaPass(); + } + else + { + context->Map(vertexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, LocalVBuffer, (u32)(s_pCurBufferPointer - LocalVBuffer)); + context->Unmap(vertexbuffer, 0); + + gfxstate->ApplyState(); + } + + D3D::context->IASetVertexBuffers(0, 1, &vertexbuffer, &bufstride, &bufoffset); + + if (IndexGenerator::GetNumTriangles() > 0) + { + u32 indexbuffersize = IndexGenerator::GetTriangleindexLen(); + ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); + if (!alphapass) + { + D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, TIBuffer, 2*indexbuffersize); + D3D::context->Unmap(indexbuffer, 0); + } + + D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); + + D3D::context->DrawIndexed(indexbuffersize, 0, 0); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumLines() > 0) + { + u32 indexbuffersize = IndexGenerator::GetLineindexLen(); + ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); + if (!alphapass) + { + D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, LIBuffer, 2*indexbuffersize); + D3D::context->Unmap(indexbuffer, 0); + } + + D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); + D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); + + D3D::context->DrawIndexed(indexbuffersize, 0, 0); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumPoints() > 0) + { + u32 indexbuffersize = IndexGenerator::GetPointindexLen(); + ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize); + if (!alphapass) + { + D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, PIBuffer, 2*indexbuffersize); + D3D::context->Unmap(indexbuffer, 0); + } + + D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0); + + D3D::context->DrawIndexed(indexbuffersize, 0, 0); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.h index 3110976530..fa15c187e1 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexManager.h @@ -1,49 +1,49 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DX11_VERTEXMANAGER_H -#define _DX11_VERTEXMANAGER_H - -#include "CPMemory.h" -#include "VertexLoader.h" - -#include "../VertexManager.h" - -namespace DX11 -{ - -enum -{ -// TODO: find sensible values for these two - NUM_VERTEXBUFFERS = 8, - NUM_INDEXBUFFERS = 10, -}; - -class VertexManager : public ::VertexManagerBase -{ -public: - VertexManager(); - ~VertexManager(); - - void Draw(u32 stride, bool alphapass); - - NativeVertexFormat* CreateNativeVertexFormat(); -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DX11_VERTEXMANAGER_H +#define _DX11_VERTEXMANAGER_H + +#include "CPMemory.h" +#include "VertexLoader.h" + +#include "../VertexManager.h" + +namespace DX11 +{ + +enum +{ +// TODO: find sensible values for these two + NUM_VERTEXBUFFERS = 8, + NUM_INDEXBUFFERS = 10, +}; + +class VertexManager : public ::VertexManagerBase +{ +public: + VertexManager(); + ~VertexManager(); + + void Draw(u32 stride, bool alphapass); + + NativeVertexFormat* CreateNativeVertexFormat(); +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.cpp index c932758344..5ec72b91d1 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.cpp @@ -1,283 +1,283 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -// Common -#include "Common.h" -#include "FileUtil.h" -#include "LinearDiskCache.h" - -// VideoCommon -#include "VideoConfig.h" -#include "Statistics.h" -#include "Profiler.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" - -// DX11 -#include "DX11_D3DBase.h" -#include "DX11_D3DShader.h" -#include "DX11_VertexShaderCache.h" -#include "DX11_Render.h" - -#include "../Main.h" - -namespace DX11 -{ - -VertexShaderCache::VSCache VertexShaderCache::vshaders; -const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry; - -static ID3D11VertexShader* SimpleVertexShader = NULL; -static ID3D11VertexShader* ClearVertexShader = NULL; -static ID3D11InputLayout* SimpleLayout = NULL; -static ID3D11InputLayout* ClearLayout = NULL; - -LinearDiskCache g_vs_disk_cache; - -ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; } -ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; } -ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; } -ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; } - -// maps the constant numbers to float indices in the constant buffer -unsigned int vs_constant_offset_table[C_VENVCONST_END]; -void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number] ] = f1; - D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+1] = f2; - D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+2] = f3; - D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+3] = f4; - D3D::gfxstate->vscbufchanged = true; -} - -void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float* f) -{ - memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4); - D3D::gfxstate->vscbufchanged = true; -} - -void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) -{ - for (unsigned int i = 0; i < count; i++) - { - memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3); - D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f; - } - D3D::gfxstate->vscbufchanged = true; -} - -void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) -{ - memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count); - D3D::gfxstate->vscbufchanged = true; -} - -// this class will load the precompiled shaders into our cache -class VertexShaderCacheInserter : public LinearDiskCacheReader { -public: - void Read(const u8* key, int key_size, const u8* value, int value_size) - { - VERTEXSHADERUID uid; - if (key_size != sizeof(uid)) - { - ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache"); - return; - } - memcpy(&uid, key, key_size); - - D3DBlob* blob = new D3DBlob(value_size, value); - VertexShaderCache::InsertByteCode(uid, blob); - blob->Release(); - } -}; - -const char simple_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float2 vTexCoord : TEXCOORD0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0;\n" - "return OUT;\n" - "}\n" -}; - -const char clear_shader_code[] = { - "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vColor0 : COLOR0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vColor0 = inColor0;\n" - "return OUT;\n" - "}\n" -}; - -VertexShaderCache::VertexShaderCache() -{ - const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - const D3D11_INPUT_ELEMENT_DESC clearelems[2] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - D3DBlob* blob; - D3D::CompileVertexShader(simple_shader_code, sizeof(simple_shader_code), &blob); - D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout); - SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob); - if (SimpleLayout == NULL || SimpleVertexShader == NULL) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__); - blob->Release(); - D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout"); - - D3D::CompileVertexShader(clear_shader_code, sizeof(clear_shader_code), &blob); - D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout); - ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob); - if (ClearLayout == NULL || ClearVertexShader == NULL) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__); - blob->Release(); - D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout"); - - Clear(); - - // these values are hardcoded, they depend on internal D3DCompile behavior - // TODO: Do this with D3DReflect or something instead - unsigned int k; - for (k = 0;k < 6;k++) vs_constant_offset_table[C_POSNORMALMATRIX+k] = 0+4*k; - for (k = 0;k < 4;k++) vs_constant_offset_table[C_PROJECTION+k] = 24+4*k; - for (k = 0;k < 4;k++) vs_constant_offset_table[C_MATERIALS+k] = 40+4*k; - for (k = 0;k < 40;k++) vs_constant_offset_table[C_LIGHTS+k] = 56+4*k; - for (k = 0;k < 24;k++) vs_constant_offset_table[C_TEXMATRICES+k] = 216+4*k; - for (k = 0;k < 64;k++) vs_constant_offset_table[C_TRANSFORMMATRICES+k] = 312+4*k; - for (k = 0;k < 32;k++) vs_constant_offset_table[C_NORMALMATRICES+k] = 568+4*k; - for (k = 0;k < 64;k++) vs_constant_offset_table[C_POSTTRANSFORMMATRICES+k] = 696+4*k; - for (k = 0;k < 4;k++) vs_constant_offset_table[C_DEPTHPARAMS+k] = 952+4*k; - - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - char cache_filename[MAX_PATH]; - sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); - VertexShaderCacheInserter inserter; - g_vs_disk_cache.OpenAndRead(cache_filename, &inserter); -} - -void VertexShaderCache::Clear() -{ - for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter) - iter->second.Destroy(); - vshaders.clear(); -} - -VertexShaderCache::~VertexShaderCache() -{ - SAFE_RELEASE(SimpleVertexShader); - SAFE_RELEASE(ClearVertexShader); - - SAFE_RELEASE(SimpleLayout); - SAFE_RELEASE(ClearLayout); - - Clear(); - g_vs_disk_cache.Sync(); - g_vs_disk_cache.Close(); -} - -bool VertexShaderCache::SetShader(u32 components) -{ - DVSTARTPROFILE(); - - VERTEXSHADERUID uid; - GetVertexShaderId(&uid, components); - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) - return (vshaders[uid].shader != NULL); - - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); - - VSCache::iterator iter; - iter = vshaders.find(uid); - if (iter != vshaders.end()) - { - iter->second.frameCount = frameCount; - const VSCacheEntry &entry = iter->second; - last_entry = &entry; - - if (entry.shader) D3D::gfxstate->SetVShader(entry.shader, iter->second.bytecode); - return (entry.shader != NULL); - } - - const char* code = GenerateVertexShaderCode(components, API_D3D11); - - D3DBlob* pbytecode = NULL; - D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode); - - if (pbytecode == NULL) - { - PanicAlert("Failed to compile Vertex Shader %s %d:\n\n%s", __FILE__, __LINE__, code); - return false; - } - g_vs_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size()); - g_vs_disk_cache.Sync(); - - bool result = InsertByteCode(uid, pbytecode); - D3D::gfxstate->SetVShader(last_entry->shader, last_entry->bytecode); - pbytecode->Release(); - return result; -} - -bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob) -{ - ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob); - if (shader == NULL) - { - PanicAlert("Failed to create vertex shader from %p size %d at %s %d\n", bcodeblob->Data(), bcodeblob->Size(), __FILE__, __LINE__); - return false; - } - // TODO: Somehow make the debug name a bit more specific - D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache"); - - // Make an entry in the table - VSCacheEntry entry; - entry.shader = shader; - entry.frameCount = frameCount; - entry.SetByteCode(bcodeblob); - - vshaders[uid] = entry; - last_entry = &vshaders[uid]; - - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); - - return true; -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +// Common +#include "Common.h" +#include "FileUtil.h" +#include "LinearDiskCache.h" + +// VideoCommon +#include "VideoConfig.h" +#include "Statistics.h" +#include "Profiler.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" + +// DX11 +#include "DX11_D3DBase.h" +#include "DX11_D3DShader.h" +#include "DX11_VertexShaderCache.h" +#include "DX11_Render.h" + +#include "../Main.h" + +namespace DX11 +{ + +VertexShaderCache::VSCache VertexShaderCache::vshaders; +const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry; + +static ID3D11VertexShader* SimpleVertexShader = NULL; +static ID3D11VertexShader* ClearVertexShader = NULL; +static ID3D11InputLayout* SimpleLayout = NULL; +static ID3D11InputLayout* ClearLayout = NULL; + +LinearDiskCache g_vs_disk_cache; + +ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; } +ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; } +ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; } +ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; } + +// maps the constant numbers to float indices in the constant buffer +unsigned int vs_constant_offset_table[C_VENVCONST_END]; +void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number] ] = f1; + D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+1] = f2; + D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+2] = f3; + D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+3] = f4; + D3D::gfxstate->vscbufchanged = true; +} + +void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float* f) +{ + memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4); + D3D::gfxstate->vscbufchanged = true; +} + +void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) +{ + for (unsigned int i = 0; i < count; i++) + { + memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3); + D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f; + } + D3D::gfxstate->vscbufchanged = true; +} + +void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) +{ + memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count); + D3D::gfxstate->vscbufchanged = true; +} + +// this class will load the precompiled shaders into our cache +class VertexShaderCacheInserter : public LinearDiskCacheReader { +public: + void Read(const u8* key, int key_size, const u8* value, int value_size) + { + VERTEXSHADERUID uid; + if (key_size != sizeof(uid)) + { + ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache"); + return; + } + memcpy(&uid, key, key_size); + + D3DBlob* blob = new D3DBlob(value_size, value); + VertexShaderCache::InsertByteCode(uid, blob); + blob->Release(); + } +}; + +const char simple_shader_code[] = { + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float2 vTexCoord : TEXCOORD0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0;\n" + "return OUT;\n" + "}\n" +}; + +const char clear_shader_code[] = { + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vColor0 = inColor0;\n" + "return OUT;\n" + "}\n" +}; + +VertexShaderCache::VertexShaderCache() +{ + const D3D11_INPUT_ELEMENT_DESC simpleelems[2] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + const D3D11_INPUT_ELEMENT_DESC clearelems[2] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + D3DBlob* blob; + D3D::CompileVertexShader(simple_shader_code, sizeof(simple_shader_code), &blob); + D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout); + SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob); + if (SimpleLayout == NULL || SimpleVertexShader == NULL) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__); + blob->Release(); + D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout"); + + D3D::CompileVertexShader(clear_shader_code, sizeof(clear_shader_code), &blob); + D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout); + ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob); + if (ClearLayout == NULL || ClearVertexShader == NULL) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__); + blob->Release(); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout"); + + Clear(); + + // these values are hardcoded, they depend on internal D3DCompile behavior + // TODO: Do this with D3DReflect or something instead + unsigned int k; + for (k = 0;k < 6;k++) vs_constant_offset_table[C_POSNORMALMATRIX+k] = 0+4*k; + for (k = 0;k < 4;k++) vs_constant_offset_table[C_PROJECTION+k] = 24+4*k; + for (k = 0;k < 4;k++) vs_constant_offset_table[C_MATERIALS+k] = 40+4*k; + for (k = 0;k < 40;k++) vs_constant_offset_table[C_LIGHTS+k] = 56+4*k; + for (k = 0;k < 24;k++) vs_constant_offset_table[C_TEXMATRICES+k] = 216+4*k; + for (k = 0;k < 64;k++) vs_constant_offset_table[C_TRANSFORMMATRICES+k] = 312+4*k; + for (k = 0;k < 32;k++) vs_constant_offset_table[C_NORMALMATRICES+k] = 568+4*k; + for (k = 0;k < 64;k++) vs_constant_offset_table[C_POSTTRANSFORMMATRICES+k] = 696+4*k; + for (k = 0;k < 4;k++) vs_constant_offset_table[C_DEPTHPARAMS+k] = 952+4*k; + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + char cache_filename[MAX_PATH]; + sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); + VertexShaderCacheInserter inserter; + g_vs_disk_cache.OpenAndRead(cache_filename, &inserter); +} + +void VertexShaderCache::Clear() +{ + for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter) + iter->second.Destroy(); + vshaders.clear(); +} + +VertexShaderCache::~VertexShaderCache() +{ + SAFE_RELEASE(SimpleVertexShader); + SAFE_RELEASE(ClearVertexShader); + + SAFE_RELEASE(SimpleLayout); + SAFE_RELEASE(ClearLayout); + + Clear(); + g_vs_disk_cache.Sync(); + g_vs_disk_cache.Close(); +} + +bool VertexShaderCache::SetShader(u32 components) +{ + DVSTARTPROFILE(); + + VERTEXSHADERUID uid; + GetVertexShaderId(&uid, components); + if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + return (vshaders[uid].shader != NULL); + + memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + + VSCache::iterator iter; + iter = vshaders.find(uid); + if (iter != vshaders.end()) + { + iter->second.frameCount = frameCount; + const VSCacheEntry &entry = iter->second; + last_entry = &entry; + + if (entry.shader) D3D::gfxstate->SetVShader(entry.shader, iter->second.bytecode); + return (entry.shader != NULL); + } + + const char* code = GenerateVertexShaderCode(components, API_D3D11); + + D3DBlob* pbytecode = NULL; + D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode); + + if (pbytecode == NULL) + { + PanicAlert("Failed to compile Vertex Shader %s %d:\n\n%s", __FILE__, __LINE__, code); + return false; + } + g_vs_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size()); + g_vs_disk_cache.Sync(); + + bool result = InsertByteCode(uid, pbytecode); + D3D::gfxstate->SetVShader(last_entry->shader, last_entry->bytecode); + pbytecode->Release(); + return result; +} + +bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob) +{ + ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob); + if (shader == NULL) + { + PanicAlert("Failed to create vertex shader from %p size %d at %s %d\n", bcodeblob->Data(), bcodeblob->Size(), __FILE__, __LINE__); + return false; + } + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache"); + + // Make an entry in the table + VSCacheEntry entry; + entry.shader = shader; + entry.frameCount = frameCount; + entry.SetByteCode(bcodeblob); + + vshaders[uid] = entry; + last_entry = &vshaders[uid]; + + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); + + return true; +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.h index fe82b138eb..acc18bd0b4 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX11/DX11_VertexShaderCache.h @@ -1,80 +1,80 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _DX11_VERTEXSHADERCACHE_H -#define _DX11_VERTEXSHADERCACHE_H - -#include - -#include "VertexShaderGen.h" -#include "DX11_D3DBase.h" - -#include "../VertexShaderCache.h" - -namespace DX11 -{ - -class VertexShaderCache : public ::VertexShaderCacheBase -{ -public: - VertexShaderCache(); - ~VertexShaderCache(); - - static void Clear(); - bool SetShader(u32 components); - - static ID3D11VertexShader* GetSimpleVertexShader(); - static ID3D11VertexShader* GetClearVertexShader(); - static ID3D11InputLayout* GetSimpleInputLayout(); - static ID3D11InputLayout* GetClearInputLayout(); - - static bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob); - - void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetVSConstant4fv(unsigned int const_number, const float* f); - void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f); - void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f); - -private: - struct VSCacheEntry - { - ID3D11VertexShader* shader; - D3DBlob* bytecode; // needed to initialize the input layout - int frameCount; - - VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {} - void SetByteCode(D3DBlob* blob) - { - SAFE_RELEASE(bytecode); - bytecode = blob; - blob->AddRef(); - } - void Destroy() - { - SAFE_RELEASE(shader); - SAFE_RELEASE(bytecode); - } - }; - typedef std::map VSCache; - - static VSCache vshaders; - static const VSCacheEntry* last_entry; -}; - -} - -#endif // _VERTEXSHADERCACHE_H +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _DX11_VERTEXSHADERCACHE_H +#define _DX11_VERTEXSHADERCACHE_H + +#include + +#include "VertexShaderGen.h" +#include "DX11_D3DBase.h" + +#include "../VertexShaderCache.h" + +namespace DX11 +{ + +class VertexShaderCache : public ::VertexShaderCacheBase +{ +public: + VertexShaderCache(); + ~VertexShaderCache(); + + static void Clear(); + bool SetShader(u32 components); + + static ID3D11VertexShader* GetSimpleVertexShader(); + static ID3D11VertexShader* GetClearVertexShader(); + static ID3D11InputLayout* GetSimpleInputLayout(); + static ID3D11InputLayout* GetClearInputLayout(); + + static bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob); + + void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetVSConstant4fv(unsigned int const_number, const float* f); + void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f); + void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f); + +private: + struct VSCacheEntry + { + ID3D11VertexShader* shader; + D3DBlob* bytecode; // needed to initialize the input layout + int frameCount; + + VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {} + void SetByteCode(D3DBlob* blob) + { + SAFE_RELEASE(bytecode); + bytecode = blob; + blob->AddRef(); + } + void Destroy() + { + SAFE_RELEASE(shader); + SAFE_RELEASE(bytecode); + } + }; + typedef std::map VSCache; + + static VSCache vshaders; + static const VSCacheEntry* last_entry; +}; + +} + +#endif // _VERTEXSHADERCACHE_H diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.cpp index a6d54ca7e1..6ea4bb43c4 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.cpp @@ -1,730 +1,730 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DX9_D3DBase.h" -#include "VideoConfig.h" -#include "DX9_Render.h" -#include "XFStructs.h" -#include "StringUtil.h" - -#pragma comment(lib, "d3d9.lib") - -namespace DX9 -{ - -// D3DX -HINSTANCE hD3DXDll = NULL; -D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA = NULL; -D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA = NULL; -D3DXCOMPILESHADERTYPE PD3DXCompileShader = NULL; - -namespace D3D -{ - -LPDIRECT3D9 D3D = NULL; // Used to create the D3DDevice -LPDIRECT3DDEVICE9 dev = NULL; // Our rendering device -LPDIRECT3DSURFACE9 back_buffer; -LPDIRECT3DSURFACE9 back_buffer_z; -D3DCAPS9 caps; -HWND hWnd; - -static int multisample; -static int resolution; -static int xres, yres; -static bool auto_depth_stencil = false; - -#define VENDOR_NVIDIA 4318 -#define VENDOR_ATI 4098 - -bool bFrameInProgress = false; - -#define MAX_ADAPTERS 4 -static Adapter adapters[MAX_ADAPTERS]; -static int numAdapters; -static int cur_adapter; - -// Value caches for state filtering -const int MaxTextureStages = 9; -const int MaxRenderStates = 210 + 46; -const int MaxTextureTypes = 33; -const int MaxSamplerSize = 13; -const int MaxSamplerTypes = 15; -static bool m_RenderStatesSet[MaxRenderStates]; -static DWORD m_RenderStates[MaxRenderStates]; -static bool m_RenderStatesChanged[MaxRenderStates]; - -static DWORD m_TextureStageStates[MaxTextureStages][MaxTextureTypes]; -static bool m_TextureStageStatesSet[MaxTextureStages][MaxTextureTypes]; -static bool m_TextureStageStatesChanged[MaxTextureStages][MaxTextureTypes]; - -static DWORD m_SamplerStates[MaxSamplerSize][MaxSamplerTypes]; -static bool m_SamplerStatesSet[MaxSamplerSize][MaxSamplerTypes]; -static bool m_SamplerStatesChanged[MaxSamplerSize][MaxSamplerTypes]; - -LPDIRECT3DBASETEXTURE9 m_Textures[16]; -LPDIRECT3DVERTEXDECLARATION9 m_VtxDecl; -LPDIRECT3DPIXELSHADER9 m_PixelShader; -LPDIRECT3DVERTEXSHADER9 m_VertexShader; - -void Enumerate(); - -int GetNumAdapters() { return numAdapters; } -const Adapter &GetAdapter(int i) { return adapters[i]; } -const Adapter &GetCurAdapter() { return adapters[cur_adapter]; } - -bool IsATIDevice() -{ - return GetCurAdapter().ident.VendorId == VENDOR_ATI; -} - - -HRESULT Init() -{ - // Create the D3D object, which is needed to create the D3DDevice. - D3D = Direct3DCreate9(D3D_SDK_VERSION); - if (!D3D) - return E_FAIL; - Enumerate(); - return S_OK; -} - -void Shutdown() -{ - D3D->Release(); - D3D = 0; -} - -void EnableAlphaToCoverage() -{ - // Each vendor has their own specific little hack. - if (GetCurAdapter().ident.VendorId == VENDOR_ATI) - D3D::SetRenderState(D3DRS_POINTSIZE, (D3DFORMAT)MAKEFOURCC('A', '2', 'M', '1')); - else - D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')); -} - -void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp) -{ - ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); - pp->hDeviceWindow = hWnd; - - if (auto_depth_stencil) - { - pp->EnableAutoDepthStencil = TRUE; - pp->AutoDepthStencilFormat = D3DFMT_D24S8; - } - else - { - pp->EnableAutoDepthStencil = FALSE; - pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN; - } - - pp->BackBufferFormat = D3DFMT_X8R8G8B8; - if (aa_mode >= (int)adapters[adapter].aa_levels.size()) - aa_mode = 0; - - pp->MultiSampleType = adapters[adapter].aa_levels[aa_mode].ms_setting; - pp->MultiSampleQuality = adapters[adapter].aa_levels[aa_mode].qual_setting; - - pp->Flags = auto_depth_stencil ? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL : 0; - - RECT client; - GetClientRect(hWnd, &client); - xres = pp->BackBufferWidth = client.right - client.left; - yres = pp->BackBufferHeight = client.bottom - client.top; - pp->SwapEffect = D3DSWAPEFFECT_DISCARD; - pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; - pp->Windowed = TRUE; -} - -void Enumerate() -{ - numAdapters = D3D::D3D->GetAdapterCount(); - - for (int i = 0; i < std::min(MAX_ADAPTERS, numAdapters); i++) - { - Adapter &a = adapters[i]; - a.aa_levels.clear(); - a.resolutions.clear(); - D3D::D3D->GetAdapterIdentifier(i, 0, &a.ident); - bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA; - - // Add SuperSamples modes - a.aa_levels.push_back(AALevel("None", D3DMULTISAMPLE_NONE, 0)); - a.aa_levels.push_back(AALevel("4x SSAA", D3DMULTISAMPLE_NONE, 0)); - a.aa_levels.push_back(AALevel("9x SSAA", D3DMULTISAMPLE_NONE, 0)); - //Add multisample modes - //disable them will they are not implemnted - /* - DWORD qlevels = 0; - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0)); - - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0)); - - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); - - if (isNvidia) - { - // CSAA support - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels)) - { - if (qlevels > 2) - { - // 8x, 8xQ are available - // See http://developer.nvidia.com/object/coverage-sampled-aa.html - a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2)); - a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); - } - } - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) - { - if (qlevels > 2) - { - // 16x, 16xQ are available - // See http://developer.nvidia.com/object/coverage-sampled-aa.html - a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4)); - a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2)); - } - } - } - */ - // Determine if INTZ is supported. Code from ATI's doc. - // http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf - a.supports_intz = D3D_OK == D3D->CheckDeviceFormat( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_INTZ); - // Also check for RAWZ (nvidia only, but the only option to get Z24 textures on sub GF8800 - a.supports_rawz = D3D_OK == D3D->CheckDeviceFormat( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RAWZ); - // Might as well check for RESZ and NULL too. - a.supports_resz = D3D_OK == D3D->CheckDeviceFormat( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RESZ); - a.supports_null = D3D_OK == D3D->CheckDeviceFormat( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_NULL); - - if (a.aa_levels.size() == 1) - { - strcpy(a.aa_levels[0].name, "(Not supported on this device)"); - } - int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8); - for (int m = 0; m < numModes; m++) - { - D3DDISPLAYMODE mode; - D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode); - - int found = -1; - for (int x = 0; x < (int)a.resolutions.size(); x++) - { - if (a.resolutions[x].xres == mode.Width && a.resolutions[x].yres == mode.Height) - { - found = x; - break; - } - } - - Resolution temp; - Resolution &r = found==-1 ? temp : a.resolutions[found]; - - sprintf(r.name, "%ix%i", mode.Width, mode.Height); - r.bitdepths.insert(mode.Format); - r.refreshes.insert(mode.RefreshRate); - if (found == -1 && mode.Width >= 640 && mode.Height >= 480) - { - r.xres = mode.Width; - r.yres = mode.Height; - a.resolutions.push_back(r); - } - } - } -} - -// dynamically picks one of the available d3dx9 dlls and loads it. -// we're first trying to load the dll Dolphin was compiled with, otherwise the most up-to-date one -HRESULT LoadD3DX9() -{ - HRESULT hr = E_FAIL; - hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str()); - if (hD3DXDll != NULL) - { - NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str()); - hr = S_OK; - } - else - { - // if that fails, try loading older dlls (no need to look for newer ones) - for (unsigned int num = D3DX_SDK_VERSION-1; num >= 24; --num) - { - hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", num).c_str()); - if (hD3DXDll != NULL) - { - NOTICE_LOG(VIDEO, "Successfully loaded %s. If you're having trouble, try updating your DX runtime first.", StringFromFormat("d3dx9_%d.dll", num).c_str()); - hr = S_OK; - break; - } - } - if (FAILED(hr)) - { - MessageBoxA(NULL, "Failed to load any D3DX9 dll, update your DX9 runtime, please", "Critical error", MB_OK | MB_ICONERROR); - return hr; - } - } - PD3DXCompileShader = (D3DXCOMPILESHADERTYPE)GetProcAddress(hD3DXDll, "D3DXCompileShader"); - if (PD3DXCompileShader == NULL) - { - MessageBoxA(NULL, "GetProcAddress failed for D3DXCompileShader!", "Critical error", MB_OK | MB_ICONERROR); - goto fail; - } - - PD3DXSaveSurfaceToFileA = (D3DXSAVESURFACETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveSurfaceToFileA"); - if (PD3DXSaveSurfaceToFileA == NULL) - { - MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveSurfaceToFileA!", "Critical error", MB_OK | MB_ICONERROR); - goto fail; - } - - PD3DXSaveTextureToFileA = (D3DXSAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveTextureToFileA"); - if (PD3DXSaveTextureToFileA == NULL) - { - MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR); - goto fail; - } - return S_OK; - -fail: - FreeLibrary(hD3DXDll); - PD3DXCompileShader = NULL; - PD3DXSaveSurfaceToFileA = NULL; - PD3DXSaveTextureToFileA = NULL; - return E_FAIL; -} - -void UnloadD3DX9() -{ - FreeLibrary(hD3DXDll); - PD3DXCompileShader = NULL; - PD3DXSaveSurfaceToFileA = NULL; - PD3DXSaveTextureToFileA = NULL; -} - -HRESULT Create(int adapter, HWND wnd, int _resolution, int aa_mode, bool auto_depth) -{ - hWnd = wnd; - multisample = aa_mode; - resolution = _resolution; - auto_depth_stencil = auto_depth; - cur_adapter = adapter; - D3DPRESENT_PARAMETERS d3dpp; - - HRESULT hr = LoadD3DX9(); - if (FAILED(hr)) return hr; - - InitPP(adapter, resolution, aa_mode, &d3dpp); - - if (FAILED(D3D->CreateDevice( - adapter, - D3DDEVTYPE_HAL, - wnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, //doesn't seem to make a difference - &d3dpp, &dev))) - { - if (FAILED(D3D->CreateDevice( - adapter, - D3DDEVTYPE_HAL, - wnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &d3dpp, &dev))) - { - MessageBox(wnd, - _T("Failed to initialize Direct3D."), - _T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR); - return E_FAIL; - } - } - - dev->GetDeviceCaps(&caps); - dev->GetRenderTarget(0, &back_buffer); - if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) - back_buffer_z = NULL; - D3D::SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE ); - D3D::SetRenderState(D3DRS_FILLMODE, g_Config.bWireFrame ? D3DFILL_WIREFRAME : D3DFILL_SOLID); - memset(m_Textures, 0, sizeof(m_Textures)); - memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet)); - memset(m_RenderStatesSet, 0, sizeof(m_RenderStatesSet)); - memset(m_SamplerStatesSet, 0, sizeof(m_SamplerStatesSet)); - memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged)); - memset(m_RenderStatesChanged, 0, sizeof(m_RenderStatesChanged)); - memset(m_SamplerStatesChanged, 0, sizeof(m_SamplerStatesChanged)); - m_VtxDecl = NULL; - m_PixelShader = NULL; - m_VertexShader = NULL; - // Device state would normally be set here - return S_OK; -} - -void Close() -{ - UnloadD3DX9(); - - if (back_buffer_z) - back_buffer_z->Release(); - back_buffer_z = NULL; - if( back_buffer ) - back_buffer->Release(); - back_buffer = NULL; - - ULONG references = dev->Release(); - if (references) - ERROR_LOG(VIDEO, "Unreleased references: %i.", references); - - dev = NULL; -} - -const D3DCAPS9 &GetCaps() -{ - return caps; -} - -const char *VertexShaderVersionString() -{ - static const char *versions[5] = {"ERROR", "vs_1_4", "vs_2_0", "vs_3_0", "vs_4_0"}; - int version = ((D3D::caps.VertexShaderVersion >> 8) & 0xFF); - return versions[std::min(4, version)]; -} - -const char *PixelShaderVersionString() -{ - static const char *versions[5] = {"ERROR", "ps_1_4", "ps_2_0", "ps_3_0", "ps_4_0"}; - int version = ((D3D::caps.PixelShaderVersion >> 8) & 0xFF); - return versions[std::min(4, version)]; -} - -LPDIRECT3DSURFACE9 GetBackBufferSurface() -{ - return back_buffer; -} - -LPDIRECT3DSURFACE9 GetBackBufferDepthSurface() -{ - return back_buffer_z; -} - -void ShowD3DError(HRESULT err) -{ - switch (err) - { - case D3DERR_DEVICELOST: - PanicAlert("Device Lost"); - break; - case D3DERR_INVALIDCALL: - PanicAlert("Invalid Call"); - break; - case D3DERR_DRIVERINTERNALERROR: - PanicAlert("Driver Internal Error"); - break; - case D3DERR_OUTOFVIDEOMEMORY: - PanicAlert("Out of vid mem"); - break; - default: - // MessageBox(0,_T("Other error or success"),_T("ERROR"),0); - break; - } -} - -void Reset() -{ - if (dev) - { - // ForgetCachedState(); - - // Can't keep a pointer around to the backbuffer surface when resetting. - SAFE_RELEASE(back_buffer_z); - SAFE_RELEASE(back_buffer); - - D3DPRESENT_PARAMETERS d3dpp; - InitPP(cur_adapter, resolution, multisample, &d3dpp); - HRESULT hr = dev->Reset(&d3dpp); - ShowD3DError(hr); - - dev->GetRenderTarget(0, &back_buffer); - if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) - back_buffer_z = NULL; - ApplyCachedState(); - } -} - -int GetBackBufferWidth() -{ - return xres; -} - -int GetBackBufferHeight() -{ - return yres; -} - -bool BeginFrame() -{ - if (bFrameInProgress) - { - PanicAlert("BeginFrame WTF"); - return false; - } - bFrameInProgress = true; - if (dev) - { - dev->BeginScene(); - return true; - } - else - return false; -} - -void EndFrame() -{ - if (!bFrameInProgress) - { - PanicAlert("EndFrame WTF"); - return; - } - bFrameInProgress = false; - dev->EndScene(); -} - -void Present() -{ - if (dev) - { - dev->Present(NULL, NULL, NULL, NULL); - } -} - -void ApplyCachedState() -{ - for (int sampler = 0; sampler < 8; sampler++) - { - for (int type = 0; type < MaxSamplerTypes; type++) - { - if(m_SamplerStatesSet[sampler][type]) - D3D::dev->SetSamplerState(sampler, (D3DSAMPLERSTATETYPE)type, m_SamplerStates[sampler][type]); - } - } - - for (int rs = 0; rs < MaxRenderStates; rs++) - { - if (m_RenderStatesSet[rs]) - D3D::dev->SetRenderState((D3DRENDERSTATETYPE)rs, m_RenderStates[rs]); - } - - // We don't bother restoring these so let's just wipe the state copy - // so no stale state is around. - memset(m_Textures, 0, sizeof(m_Textures)); - memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet)); - memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged)); - m_VtxDecl = NULL; - m_PixelShader = NULL; - m_VertexShader = NULL; -} - -void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture) -{ - if (m_Textures[Stage] != pTexture) - { - m_Textures[Stage] = pTexture; - D3D::dev->SetTexture(Stage, pTexture); - } -} - -void RefreshRenderState(D3DRENDERSTATETYPE State) -{ - if(m_RenderStatesSet[State] && m_RenderStatesChanged[State]) - { - D3D::dev->SetRenderState(State, m_RenderStates[State]); - m_RenderStatesChanged[State] = false; - } -} - -void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) -{ - if (m_RenderStates[State] != Value || !m_RenderStatesSet[State]) - { - m_RenderStates[State] = Value; - m_RenderStatesSet[State] = true; - m_RenderStatesChanged[State] = false; - D3D::dev->SetRenderState(State, Value); - } -} - -void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value) -{ - if (m_RenderStates[State] != Value || !m_RenderStatesSet[State]) - { - m_RenderStatesChanged[State] = m_RenderStatesSet[State]; - D3D::dev->SetRenderState(State, Value); - } - else - { - m_RenderStatesChanged[State] = false; - } -} - -void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) -{ - if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type]) - { - m_TextureStageStates[Stage][Type] = Value; - m_TextureStageStatesSet[Stage][Type]=true; - m_TextureStageStatesChanged[Stage][Type]=false; - D3D::dev->SetTextureStageState(Stage, Type, Value); - } -} - -void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type) -{ - if(m_TextureStageStatesSet[Stage][Type] && m_TextureStageStatesChanged[Stage][Type]) - { - D3D::dev->SetTextureStageState(Stage, Type, m_TextureStageStates[Stage][Type]); - m_TextureStageStatesChanged[Stage][Type] = false; - } -} - -void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) -{ - if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type]) - { - m_TextureStageStatesChanged[Stage][Type] = m_TextureStageStatesSet[Stage][Type]; - D3D::dev->SetTextureStageState(Stage, Type, Value); - } - else - { - m_TextureStageStatesChanged[Stage][Type] = false; - } -} - -void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) -{ - if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type]) - { - m_SamplerStates[Sampler][Type] = Value; - m_SamplerStatesSet[Sampler][Type] = true; - m_SamplerStatesChanged[Sampler][Type] = false; - D3D::dev->SetSamplerState(Sampler, Type, Value); - } -} - -void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type) -{ - if(m_SamplerStatesSet[Sampler][Type] && m_SamplerStatesChanged[Sampler][Type]) - { - D3D::dev->SetSamplerState(Sampler, Type, m_SamplerStates[Sampler][Type]); - m_SamplerStatesChanged[Sampler][Type] = false; - } -} - -void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) -{ - if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type]) - { - m_SamplerStatesChanged[Sampler][Type] = m_SamplerStatesSet[Sampler][Type]; - D3D::dev->SetSamplerState(Sampler, Type, Value); - } - else - { - m_SamplerStatesChanged[Sampler][Type] = false; - } -} - -void RefreshVertexDeclaration() -{ - if (m_VtxDecl) - { - D3D::dev->SetVertexDeclaration(m_VtxDecl); - } -} - -void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl) -{ - if (!decl) { - m_VtxDecl = NULL; - return; - } - if (decl != m_VtxDecl) - { - D3D::dev->SetVertexDeclaration(decl); - m_VtxDecl = decl; - } -} - -void RefreshVertexShader() -{ - if (m_VertexShader) - { - D3D::dev->SetVertexShader(m_VertexShader); - } -} - -void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader) -{ - if (!shader) { - m_VertexShader = NULL; - return; - } - if (shader != m_VertexShader) - { - D3D::dev->SetVertexShader(shader); - m_VertexShader = shader; - } -} - -void RefreshPixelShader() -{ - if (m_PixelShader) - { - D3D::dev->SetPixelShader(m_PixelShader); - } -} - -void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader) -{ - if (!shader) { - m_PixelShader = NULL; - return; - } - if (shader != m_PixelShader) - { - D3D::dev->SetPixelShader(shader); - m_PixelShader = shader; - } -} - - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DX9_D3DBase.h" +#include "VideoConfig.h" +#include "DX9_Render.h" +#include "XFStructs.h" +#include "StringUtil.h" + +#pragma comment(lib, "d3d9.lib") + +namespace DX9 +{ + +// D3DX +HINSTANCE hD3DXDll = NULL; +D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA = NULL; +D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA = NULL; +D3DXCOMPILESHADERTYPE PD3DXCompileShader = NULL; + +namespace D3D +{ + +LPDIRECT3D9 D3D = NULL; // Used to create the D3DDevice +LPDIRECT3DDEVICE9 dev = NULL; // Our rendering device +LPDIRECT3DSURFACE9 back_buffer; +LPDIRECT3DSURFACE9 back_buffer_z; +D3DCAPS9 caps; +HWND hWnd; + +static int multisample; +static int resolution; +static int xres, yres; +static bool auto_depth_stencil = false; + +#define VENDOR_NVIDIA 4318 +#define VENDOR_ATI 4098 + +bool bFrameInProgress = false; + +#define MAX_ADAPTERS 4 +static Adapter adapters[MAX_ADAPTERS]; +static int numAdapters; +static int cur_adapter; + +// Value caches for state filtering +const int MaxTextureStages = 9; +const int MaxRenderStates = 210 + 46; +const int MaxTextureTypes = 33; +const int MaxSamplerSize = 13; +const int MaxSamplerTypes = 15; +static bool m_RenderStatesSet[MaxRenderStates]; +static DWORD m_RenderStates[MaxRenderStates]; +static bool m_RenderStatesChanged[MaxRenderStates]; + +static DWORD m_TextureStageStates[MaxTextureStages][MaxTextureTypes]; +static bool m_TextureStageStatesSet[MaxTextureStages][MaxTextureTypes]; +static bool m_TextureStageStatesChanged[MaxTextureStages][MaxTextureTypes]; + +static DWORD m_SamplerStates[MaxSamplerSize][MaxSamplerTypes]; +static bool m_SamplerStatesSet[MaxSamplerSize][MaxSamplerTypes]; +static bool m_SamplerStatesChanged[MaxSamplerSize][MaxSamplerTypes]; + +LPDIRECT3DBASETEXTURE9 m_Textures[16]; +LPDIRECT3DVERTEXDECLARATION9 m_VtxDecl; +LPDIRECT3DPIXELSHADER9 m_PixelShader; +LPDIRECT3DVERTEXSHADER9 m_VertexShader; + +void Enumerate(); + +int GetNumAdapters() { return numAdapters; } +const Adapter &GetAdapter(int i) { return adapters[i]; } +const Adapter &GetCurAdapter() { return adapters[cur_adapter]; } + +bool IsATIDevice() +{ + return GetCurAdapter().ident.VendorId == VENDOR_ATI; +} + + +HRESULT Init() +{ + // Create the D3D object, which is needed to create the D3DDevice. + D3D = Direct3DCreate9(D3D_SDK_VERSION); + if (!D3D) + return E_FAIL; + Enumerate(); + return S_OK; +} + +void Shutdown() +{ + D3D->Release(); + D3D = 0; +} + +void EnableAlphaToCoverage() +{ + // Each vendor has their own specific little hack. + if (GetCurAdapter().ident.VendorId == VENDOR_ATI) + D3D::SetRenderState(D3DRS_POINTSIZE, (D3DFORMAT)MAKEFOURCC('A', '2', 'M', '1')); + else + D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')); +} + +void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp) +{ + ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); + pp->hDeviceWindow = hWnd; + + if (auto_depth_stencil) + { + pp->EnableAutoDepthStencil = TRUE; + pp->AutoDepthStencilFormat = D3DFMT_D24S8; + } + else + { + pp->EnableAutoDepthStencil = FALSE; + pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + + pp->BackBufferFormat = D3DFMT_X8R8G8B8; + if (aa_mode >= (int)adapters[adapter].aa_levels.size()) + aa_mode = 0; + + pp->MultiSampleType = adapters[adapter].aa_levels[aa_mode].ms_setting; + pp->MultiSampleQuality = adapters[adapter].aa_levels[aa_mode].qual_setting; + + pp->Flags = auto_depth_stencil ? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL : 0; + + RECT client; + GetClientRect(hWnd, &client); + xres = pp->BackBufferWidth = client.right - client.left; + yres = pp->BackBufferHeight = client.bottom - client.top; + pp->SwapEffect = D3DSWAPEFFECT_DISCARD; + pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; + pp->Windowed = TRUE; +} + +void Enumerate() +{ + numAdapters = D3D::D3D->GetAdapterCount(); + + for (int i = 0; i < std::min(MAX_ADAPTERS, numAdapters); i++) + { + Adapter &a = adapters[i]; + a.aa_levels.clear(); + a.resolutions.clear(); + D3D::D3D->GetAdapterIdentifier(i, 0, &a.ident); + bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA; + + // Add SuperSamples modes + a.aa_levels.push_back(AALevel("None", D3DMULTISAMPLE_NONE, 0)); + a.aa_levels.push_back(AALevel("4x SSAA", D3DMULTISAMPLE_NONE, 0)); + a.aa_levels.push_back(AALevel("9x SSAA", D3DMULTISAMPLE_NONE, 0)); + //Add multisample modes + //disable them will they are not implemnted + /* + DWORD qlevels = 0; + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0)); + + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0)); + + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); + + if (isNvidia) + { + // CSAA support + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels)) + { + if (qlevels > 2) + { + // 8x, 8xQ are available + // See http://developer.nvidia.com/object/coverage-sampled-aa.html + a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2)); + a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); + } + } + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) + { + if (qlevels > 2) + { + // 16x, 16xQ are available + // See http://developer.nvidia.com/object/coverage-sampled-aa.html + a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4)); + a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2)); + } + } + } + */ + // Determine if INTZ is supported. Code from ATI's doc. + // http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf + a.supports_intz = D3D_OK == D3D->CheckDeviceFormat( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_INTZ); + // Also check for RAWZ (nvidia only, but the only option to get Z24 textures on sub GF8800 + a.supports_rawz = D3D_OK == D3D->CheckDeviceFormat( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RAWZ); + // Might as well check for RESZ and NULL too. + a.supports_resz = D3D_OK == D3D->CheckDeviceFormat( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_RESZ); + a.supports_null = D3D_OK == D3D->CheckDeviceFormat( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, + D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, FOURCC_NULL); + + if (a.aa_levels.size() == 1) + { + strcpy(a.aa_levels[0].name, "(Not supported on this device)"); + } + int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8); + for (int m = 0; m < numModes; m++) + { + D3DDISPLAYMODE mode; + D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode); + + int found = -1; + for (int x = 0; x < (int)a.resolutions.size(); x++) + { + if (a.resolutions[x].xres == mode.Width && a.resolutions[x].yres == mode.Height) + { + found = x; + break; + } + } + + Resolution temp; + Resolution &r = found==-1 ? temp : a.resolutions[found]; + + sprintf(r.name, "%ix%i", mode.Width, mode.Height); + r.bitdepths.insert(mode.Format); + r.refreshes.insert(mode.RefreshRate); + if (found == -1 && mode.Width >= 640 && mode.Height >= 480) + { + r.xres = mode.Width; + r.yres = mode.Height; + a.resolutions.push_back(r); + } + } + } +} + +// dynamically picks one of the available d3dx9 dlls and loads it. +// we're first trying to load the dll Dolphin was compiled with, otherwise the most up-to-date one +HRESULT LoadD3DX9() +{ + HRESULT hr = E_FAIL; + hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str()); + if (hD3DXDll != NULL) + { + NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx9_%d.dll", D3DX_SDK_VERSION).c_str()); + hr = S_OK; + } + else + { + // if that fails, try loading older dlls (no need to look for newer ones) + for (unsigned int num = D3DX_SDK_VERSION-1; num >= 24; --num) + { + hD3DXDll = LoadLibraryA(StringFromFormat("d3dx9_%d.dll", num).c_str()); + if (hD3DXDll != NULL) + { + NOTICE_LOG(VIDEO, "Successfully loaded %s. If you're having trouble, try updating your DX runtime first.", StringFromFormat("d3dx9_%d.dll", num).c_str()); + hr = S_OK; + break; + } + } + if (FAILED(hr)) + { + MessageBoxA(NULL, "Failed to load any D3DX9 dll, update your DX9 runtime, please", "Critical error", MB_OK | MB_ICONERROR); + return hr; + } + } + PD3DXCompileShader = (D3DXCOMPILESHADERTYPE)GetProcAddress(hD3DXDll, "D3DXCompileShader"); + if (PD3DXCompileShader == NULL) + { + MessageBoxA(NULL, "GetProcAddress failed for D3DXCompileShader!", "Critical error", MB_OK | MB_ICONERROR); + goto fail; + } + + PD3DXSaveSurfaceToFileA = (D3DXSAVESURFACETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveSurfaceToFileA"); + if (PD3DXSaveSurfaceToFileA == NULL) + { + MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveSurfaceToFileA!", "Critical error", MB_OK | MB_ICONERROR); + goto fail; + } + + PD3DXSaveTextureToFileA = (D3DXSAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DXSaveTextureToFileA"); + if (PD3DXSaveTextureToFileA == NULL) + { + MessageBoxA(NULL, "GetProcAddress failed for D3DXSaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR); + goto fail; + } + return S_OK; + +fail: + FreeLibrary(hD3DXDll); + PD3DXCompileShader = NULL; + PD3DXSaveSurfaceToFileA = NULL; + PD3DXSaveTextureToFileA = NULL; + return E_FAIL; +} + +void UnloadD3DX9() +{ + FreeLibrary(hD3DXDll); + PD3DXCompileShader = NULL; + PD3DXSaveSurfaceToFileA = NULL; + PD3DXSaveTextureToFileA = NULL; +} + +HRESULT Create(int adapter, HWND wnd, int _resolution, int aa_mode, bool auto_depth) +{ + hWnd = wnd; + multisample = aa_mode; + resolution = _resolution; + auto_depth_stencil = auto_depth; + cur_adapter = adapter; + D3DPRESENT_PARAMETERS d3dpp; + + HRESULT hr = LoadD3DX9(); + if (FAILED(hr)) return hr; + + InitPP(adapter, resolution, aa_mode, &d3dpp); + + if (FAILED(D3D->CreateDevice( + adapter, + D3DDEVTYPE_HAL, + wnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, //doesn't seem to make a difference + &d3dpp, &dev))) + { + if (FAILED(D3D->CreateDevice( + adapter, + D3DDEVTYPE_HAL, + wnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &dev))) + { + MessageBox(wnd, + _T("Failed to initialize Direct3D."), + _T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR); + return E_FAIL; + } + } + + dev->GetDeviceCaps(&caps); + dev->GetRenderTarget(0, &back_buffer); + if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) + back_buffer_z = NULL; + D3D::SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE ); + D3D::SetRenderState(D3DRS_FILLMODE, g_Config.bWireFrame ? D3DFILL_WIREFRAME : D3DFILL_SOLID); + memset(m_Textures, 0, sizeof(m_Textures)); + memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet)); + memset(m_RenderStatesSet, 0, sizeof(m_RenderStatesSet)); + memset(m_SamplerStatesSet, 0, sizeof(m_SamplerStatesSet)); + memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged)); + memset(m_RenderStatesChanged, 0, sizeof(m_RenderStatesChanged)); + memset(m_SamplerStatesChanged, 0, sizeof(m_SamplerStatesChanged)); + m_VtxDecl = NULL; + m_PixelShader = NULL; + m_VertexShader = NULL; + // Device state would normally be set here + return S_OK; +} + +void Close() +{ + UnloadD3DX9(); + + if (back_buffer_z) + back_buffer_z->Release(); + back_buffer_z = NULL; + if( back_buffer ) + back_buffer->Release(); + back_buffer = NULL; + + ULONG references = dev->Release(); + if (references) + ERROR_LOG(VIDEO, "Unreleased references: %i.", references); + + dev = NULL; +} + +const D3DCAPS9 &GetCaps() +{ + return caps; +} + +const char *VertexShaderVersionString() +{ + static const char *versions[5] = {"ERROR", "vs_1_4", "vs_2_0", "vs_3_0", "vs_4_0"}; + int version = ((D3D::caps.VertexShaderVersion >> 8) & 0xFF); + return versions[std::min(4, version)]; +} + +const char *PixelShaderVersionString() +{ + static const char *versions[5] = {"ERROR", "ps_1_4", "ps_2_0", "ps_3_0", "ps_4_0"}; + int version = ((D3D::caps.PixelShaderVersion >> 8) & 0xFF); + return versions[std::min(4, version)]; +} + +LPDIRECT3DSURFACE9 GetBackBufferSurface() +{ + return back_buffer; +} + +LPDIRECT3DSURFACE9 GetBackBufferDepthSurface() +{ + return back_buffer_z; +} + +void ShowD3DError(HRESULT err) +{ + switch (err) + { + case D3DERR_DEVICELOST: + PanicAlert("Device Lost"); + break; + case D3DERR_INVALIDCALL: + PanicAlert("Invalid Call"); + break; + case D3DERR_DRIVERINTERNALERROR: + PanicAlert("Driver Internal Error"); + break; + case D3DERR_OUTOFVIDEOMEMORY: + PanicAlert("Out of vid mem"); + break; + default: + // MessageBox(0,_T("Other error or success"),_T("ERROR"),0); + break; + } +} + +void Reset() +{ + if (dev) + { + // ForgetCachedState(); + + // Can't keep a pointer around to the backbuffer surface when resetting. + SAFE_RELEASE(back_buffer_z); + SAFE_RELEASE(back_buffer); + + D3DPRESENT_PARAMETERS d3dpp; + InitPP(cur_adapter, resolution, multisample, &d3dpp); + HRESULT hr = dev->Reset(&d3dpp); + ShowD3DError(hr); + + dev->GetRenderTarget(0, &back_buffer); + if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) + back_buffer_z = NULL; + ApplyCachedState(); + } +} + +int GetBackBufferWidth() +{ + return xres; +} + +int GetBackBufferHeight() +{ + return yres; +} + +bool BeginFrame() +{ + if (bFrameInProgress) + { + PanicAlert("BeginFrame WTF"); + return false; + } + bFrameInProgress = true; + if (dev) + { + dev->BeginScene(); + return true; + } + else + return false; +} + +void EndFrame() +{ + if (!bFrameInProgress) + { + PanicAlert("EndFrame WTF"); + return; + } + bFrameInProgress = false; + dev->EndScene(); +} + +void Present() +{ + if (dev) + { + dev->Present(NULL, NULL, NULL, NULL); + } +} + +void ApplyCachedState() +{ + for (int sampler = 0; sampler < 8; sampler++) + { + for (int type = 0; type < MaxSamplerTypes; type++) + { + if(m_SamplerStatesSet[sampler][type]) + D3D::dev->SetSamplerState(sampler, (D3DSAMPLERSTATETYPE)type, m_SamplerStates[sampler][type]); + } + } + + for (int rs = 0; rs < MaxRenderStates; rs++) + { + if (m_RenderStatesSet[rs]) + D3D::dev->SetRenderState((D3DRENDERSTATETYPE)rs, m_RenderStates[rs]); + } + + // We don't bother restoring these so let's just wipe the state copy + // so no stale state is around. + memset(m_Textures, 0, sizeof(m_Textures)); + memset(m_TextureStageStatesSet, 0, sizeof(m_TextureStageStatesSet)); + memset(m_TextureStageStatesChanged, 0, sizeof(m_TextureStageStatesChanged)); + m_VtxDecl = NULL; + m_PixelShader = NULL; + m_VertexShader = NULL; +} + +void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture) +{ + if (m_Textures[Stage] != pTexture) + { + m_Textures[Stage] = pTexture; + D3D::dev->SetTexture(Stage, pTexture); + } +} + +void RefreshRenderState(D3DRENDERSTATETYPE State) +{ + if(m_RenderStatesSet[State] && m_RenderStatesChanged[State]) + { + D3D::dev->SetRenderState(State, m_RenderStates[State]); + m_RenderStatesChanged[State] = false; + } +} + +void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) +{ + if (m_RenderStates[State] != Value || !m_RenderStatesSet[State]) + { + m_RenderStates[State] = Value; + m_RenderStatesSet[State] = true; + m_RenderStatesChanged[State] = false; + D3D::dev->SetRenderState(State, Value); + } +} + +void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value) +{ + if (m_RenderStates[State] != Value || !m_RenderStatesSet[State]) + { + m_RenderStatesChanged[State] = m_RenderStatesSet[State]; + D3D::dev->SetRenderState(State, Value); + } + else + { + m_RenderStatesChanged[State] = false; + } +} + +void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) +{ + if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type]) + { + m_TextureStageStates[Stage][Type] = Value; + m_TextureStageStatesSet[Stage][Type]=true; + m_TextureStageStatesChanged[Stage][Type]=false; + D3D::dev->SetTextureStageState(Stage, Type, Value); + } +} + +void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type) +{ + if(m_TextureStageStatesSet[Stage][Type] && m_TextureStageStatesChanged[Stage][Type]) + { + D3D::dev->SetTextureStageState(Stage, Type, m_TextureStageStates[Stage][Type]); + m_TextureStageStatesChanged[Stage][Type] = false; + } +} + +void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) +{ + if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type]) + { + m_TextureStageStatesChanged[Stage][Type] = m_TextureStageStatesSet[Stage][Type]; + D3D::dev->SetTextureStageState(Stage, Type, Value); + } + else + { + m_TextureStageStatesChanged[Stage][Type] = false; + } +} + +void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) +{ + if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type]) + { + m_SamplerStates[Sampler][Type] = Value; + m_SamplerStatesSet[Sampler][Type] = true; + m_SamplerStatesChanged[Sampler][Type] = false; + D3D::dev->SetSamplerState(Sampler, Type, Value); + } +} + +void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type) +{ + if(m_SamplerStatesSet[Sampler][Type] && m_SamplerStatesChanged[Sampler][Type]) + { + D3D::dev->SetSamplerState(Sampler, Type, m_SamplerStates[Sampler][Type]); + m_SamplerStatesChanged[Sampler][Type] = false; + } +} + +void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) +{ + if (m_SamplerStates[Sampler][Type] != Value || !m_SamplerStatesSet[Sampler][Type]) + { + m_SamplerStatesChanged[Sampler][Type] = m_SamplerStatesSet[Sampler][Type]; + D3D::dev->SetSamplerState(Sampler, Type, Value); + } + else + { + m_SamplerStatesChanged[Sampler][Type] = false; + } +} + +void RefreshVertexDeclaration() +{ + if (m_VtxDecl) + { + D3D::dev->SetVertexDeclaration(m_VtxDecl); + } +} + +void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl) +{ + if (!decl) { + m_VtxDecl = NULL; + return; + } + if (decl != m_VtxDecl) + { + D3D::dev->SetVertexDeclaration(decl); + m_VtxDecl = decl; + } +} + +void RefreshVertexShader() +{ + if (m_VertexShader) + { + D3D::dev->SetVertexShader(m_VertexShader); + } +} + +void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader) +{ + if (!shader) { + m_VertexShader = NULL; + return; + } + if (shader != m_VertexShader) + { + D3D::dev->SetVertexShader(shader); + m_VertexShader = shader; + } +} + +void RefreshPixelShader() +{ + if (m_PixelShader) + { + D3D::dev->SetPixelShader(m_PixelShader); + } +} + +void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader) +{ + if (!shader) { + m_PixelShader = NULL; + return; + } + if (shader != m_PixelShader) + { + D3D::dev->SetPixelShader(shader); + m_PixelShader = shader; + } +} + + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.h index 8ebdc47de0..52ac694d40 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DBase.h @@ -1,165 +1,165 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _D3DBASE_H -#define _D3DBASE_H - -#include -#include - -#include - -#include "Common.h" - -namespace DX9 -{ - -namespace D3D -{ - -#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; } -#define SAFE_DELETE(x) { delete (x); (x) = NULL; } - -// From http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf -// Magic FourCC's to unlock undocumented D3D9 features: - -// Z texture formats -#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))) -#define FOURCC_RAWZ ((D3DFORMAT)(MAKEFOURCC('R','A','W','Z'))) -#define FOURCC_DF24 ((D3DFORMAT)(MAKEFOURCC('D','F','2','4'))) -#define FOURCC_DF16 ((D3DFORMAT)(MAKEFOURCC('D','F','1','6'))) - -// Depth buffer resolve: -#define FOURCC_RESZ ((D3DFORMAT)(MAKEFOURCC('R','E','S','Z'))) -#define RESZ_CODE 0x7fa05000 - -// Null render target to do Z-only shadow maps: (probably not useful for Dolphin) -#define FOURCC_NULL ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))) - -bool IsATIDevice(); -HRESULT Init(); -HRESULT Create(int adapter, HWND wnd, int resolution, int aa_mode, bool auto_depth); -void Close(); -void Shutdown(); - -// Direct access to the device. -extern LPDIRECT3DDEVICE9 dev; -extern bool bFrameInProgress; - -void Reset(); -bool BeginFrame(); -void EndFrame(); -void Present(); -bool CanUseINTZ(); - -int GetBackBufferWidth(); -int GetBackBufferHeight(); -LPDIRECT3DSURFACE9 GetBackBufferSurface(); -LPDIRECT3DSURFACE9 GetBackBufferDepthSurface(); -LPDIRECT3DVERTEXBUFFER9 GetquadVB(); -LPDIRECT3DVERTEXDECLARATION9 GetBasicvertexDecl(); -const D3DCAPS9 &GetCaps(); -const char *PixelShaderVersionString(); -const char *VertexShaderVersionString(); -void ShowD3DError(HRESULT err); - -// The following are "filtered" versions of the corresponding D3Ddev-> functions. -void SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture); -void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value); -void RefreshRenderState(D3DRENDERSTATETYPE State); -void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value); - -void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); -void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type); -void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); - -void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); -void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type); -void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); - -void RefreshVertexDeclaration(); -void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl); - -void RefreshVertexShader(); -void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader); - -void RefreshPixelShader(); -void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader); - -void ApplyCachedState(); - -// Utility functions for vendor specific hacks. So far, just the one. -void EnableAlphaToCoverage(); - -struct Resolution -{ - char name[32]; - int xres; - int yres; - std::set bitdepths; - std::set refreshes; -}; - -struct AALevel -{ - AALevel(const char *n, D3DMULTISAMPLE_TYPE m, int q) { - strncpy(name, n, 32); - name[31] = '\0'; - ms_setting = m; - qual_setting = q; - } - char name[32]; - D3DMULTISAMPLE_TYPE ms_setting; - int qual_setting; -}; - -struct Adapter -{ - D3DADAPTER_IDENTIFIER9 ident; - std::vector resolutions; - std::vector aa_levels; - bool supports_alpha_to_coverage; - - // Magic render targets, see the top of this file. - bool supports_intz; - bool supports_rawz; - bool supports_resz; - bool supports_null; -}; - -const Adapter &GetAdapter(int i); -const Adapter &GetCurAdapter(); -int GetNumAdapters(); - -} // namespace - - -// Used to not require the SDK and runtime versions to match: -// Linking with d3dx9.lib makes the most recent d3dx9_xx.dll of the -// compiler's SDK an actually unnecessary requirement. -// Add any d3dx9 functions which you want to use here and load them in LoadD3DX9() -typedef HRESULT (WINAPI* D3DXSAVESURFACETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DSURFACE9, CONST PALETTEENTRY*, CONST RECT*); -typedef HRESULT (WINAPI* D3DXSAVETEXTURETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DBASETEXTURE9, CONST PALETTEENTRY*); -typedef HRESULT (WINAPI* D3DXCOMPILESHADERTYPE)(LPCSTR, UINT, CONST D3DXMACRO*, LPD3DXINCLUDE, LPCSTR, LPCSTR, DWORD, LPD3DXBUFFER*, LPD3DXBUFFER*, LPD3DXCONSTANTTABLE*); - -extern D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA; -extern D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA; -extern D3DXCOMPILESHADERTYPE PD3DXCompileShader; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _D3DBASE_H +#define _D3DBASE_H + +#include +#include + +#include + +#include "Common.h" + +namespace DX9 +{ + +namespace D3D +{ + +#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; } +#define SAFE_DELETE(x) { delete (x); (x) = NULL; } + +// From http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf +// Magic FourCC's to unlock undocumented D3D9 features: + +// Z texture formats +#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))) +#define FOURCC_RAWZ ((D3DFORMAT)(MAKEFOURCC('R','A','W','Z'))) +#define FOURCC_DF24 ((D3DFORMAT)(MAKEFOURCC('D','F','2','4'))) +#define FOURCC_DF16 ((D3DFORMAT)(MAKEFOURCC('D','F','1','6'))) + +// Depth buffer resolve: +#define FOURCC_RESZ ((D3DFORMAT)(MAKEFOURCC('R','E','S','Z'))) +#define RESZ_CODE 0x7fa05000 + +// Null render target to do Z-only shadow maps: (probably not useful for Dolphin) +#define FOURCC_NULL ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))) + +bool IsATIDevice(); +HRESULT Init(); +HRESULT Create(int adapter, HWND wnd, int resolution, int aa_mode, bool auto_depth); +void Close(); +void Shutdown(); + +// Direct access to the device. +extern LPDIRECT3DDEVICE9 dev; +extern bool bFrameInProgress; + +void Reset(); +bool BeginFrame(); +void EndFrame(); +void Present(); +bool CanUseINTZ(); + +int GetBackBufferWidth(); +int GetBackBufferHeight(); +LPDIRECT3DSURFACE9 GetBackBufferSurface(); +LPDIRECT3DSURFACE9 GetBackBufferDepthSurface(); +LPDIRECT3DVERTEXBUFFER9 GetquadVB(); +LPDIRECT3DVERTEXDECLARATION9 GetBasicvertexDecl(); +const D3DCAPS9 &GetCaps(); +const char *PixelShaderVersionString(); +const char *VertexShaderVersionString(); +void ShowD3DError(HRESULT err); + +// The following are "filtered" versions of the corresponding D3Ddev-> functions. +void SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture); +void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value); +void RefreshRenderState(D3DRENDERSTATETYPE State); +void ChangeRenderState(D3DRENDERSTATETYPE State, DWORD Value); + +void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); +void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type); +void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); + +void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); +void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type); +void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); + +void RefreshVertexDeclaration(); +void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl); + +void RefreshVertexShader(); +void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader); + +void RefreshPixelShader(); +void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader); + +void ApplyCachedState(); + +// Utility functions for vendor specific hacks. So far, just the one. +void EnableAlphaToCoverage(); + +struct Resolution +{ + char name[32]; + int xres; + int yres; + std::set bitdepths; + std::set refreshes; +}; + +struct AALevel +{ + AALevel(const char *n, D3DMULTISAMPLE_TYPE m, int q) { + strncpy(name, n, 32); + name[31] = '\0'; + ms_setting = m; + qual_setting = q; + } + char name[32]; + D3DMULTISAMPLE_TYPE ms_setting; + int qual_setting; +}; + +struct Adapter +{ + D3DADAPTER_IDENTIFIER9 ident; + std::vector resolutions; + std::vector aa_levels; + bool supports_alpha_to_coverage; + + // Magic render targets, see the top of this file. + bool supports_intz; + bool supports_rawz; + bool supports_resz; + bool supports_null; +}; + +const Adapter &GetAdapter(int i); +const Adapter &GetCurAdapter(); +int GetNumAdapters(); + +} // namespace + + +// Used to not require the SDK and runtime versions to match: +// Linking with d3dx9.lib makes the most recent d3dx9_xx.dll of the +// compiler's SDK an actually unnecessary requirement. +// Add any d3dx9 functions which you want to use here and load them in LoadD3DX9() +typedef HRESULT (WINAPI* D3DXSAVESURFACETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DSURFACE9, CONST PALETTEENTRY*, CONST RECT*); +typedef HRESULT (WINAPI* D3DXSAVETEXTURETOFILEATYPE)(LPCSTR, D3DXIMAGE_FILEFORMAT, LPDIRECT3DBASETEXTURE9, CONST PALETTEENTRY*); +typedef HRESULT (WINAPI* D3DXCOMPILESHADERTYPE)(LPCSTR, UINT, CONST D3DXMACRO*, LPD3DXINCLUDE, LPCSTR, LPCSTR, DWORD, LPD3DXBUFFER*, LPD3DXBUFFER*, LPD3DXCONSTANTTABLE*); + +extern D3DXSAVESURFACETOFILEATYPE PD3DXSaveSurfaceToFileA; +extern D3DXSAVETEXTURETOFILEATYPE PD3DXSaveTextureToFileA; +extern D3DXCOMPILESHADERTYPE PD3DXCompileShader; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.cpp index c7fd8764ee..ba174f32f4 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.cpp @@ -1,150 +1,150 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -#include "VideoConfig.h" -#include "DX9_D3DShader.h" - -namespace DX9 -{ - -namespace D3D -{ - -// Bytecode->shader. -LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len) -{ - LPDIRECT3DVERTEXSHADER9 v_shader; - HRESULT hr = D3D::dev->CreateVertexShader((DWORD *)bytecode, &v_shader); - if (FAILED(hr)) - v_shader = 0; - return v_shader; -} - -// Code->bytecode. -bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen) -{ - //try to compile - LPD3DXBUFFER shaderBuffer = 0; - LPD3DXBUFFER errorBuffer = 0; - HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::VertexShaderVersionString(), - 0, &shaderBuffer, &errorBuffer, 0); - if (FAILED(hr)) - { - //compilation error - if (g_ActiveConfig.bShowShaderErrors) { - std::string hello = (char*)errorBuffer->GetBufferPointer(); - hello += "\n\n"; - hello += code; - MessageBoxA(0, hello.c_str(), "Error compiling vertex shader", MB_ICONERROR); - } - *bytecode = 0; - *bytecodelen = 0; - } - else if (SUCCEEDED(hr)) - { - *bytecodelen = shaderBuffer->GetBufferSize(); - *bytecode = new u8[*bytecodelen]; - memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen); - } - - //cleanup - if (shaderBuffer) - shaderBuffer->Release(); - if (errorBuffer) - errorBuffer->Release(); - return SUCCEEDED(hr) ? true : false; -} - - -// Bytecode->shader. -LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len) -{ - LPDIRECT3DPIXELSHADER9 p_shader; - HRESULT hr = D3D::dev->CreatePixelShader((DWORD *)bytecode, &p_shader); - if (FAILED(hr)) - p_shader = 0; - return p_shader; -} - - -bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen) -{ - LPD3DXBUFFER shaderBuffer = 0; - LPD3DXBUFFER errorBuffer = 0; - - // Someone: - // For some reason, I had this kind of errors : "Shader uses texture addressing operations - // in a dependency chain that is too complex for the target shader model (ps_2_0) to handle." - HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::PixelShaderVersionString(), - 0, &shaderBuffer, &errorBuffer, 0); - - if (FAILED(hr)) - { - if (g_ActiveConfig.bShowShaderErrors) { - std::string hello = (char*)errorBuffer->GetBufferPointer(); - hello += "\n\n"; - hello += code; - MessageBoxA(0, hello.c_str(), "Error compiling pixel shader", MB_ICONERROR); - } - *bytecode = 0; - *bytecodelen = 0; - } - else if (SUCCEEDED(hr)) - { - *bytecodelen = shaderBuffer->GetBufferSize(); - *bytecode = new u8[*bytecodelen]; - memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen); - } - - //cleanup - if (shaderBuffer) - shaderBuffer->Release(); - if (errorBuffer) - errorBuffer->Release(); - return SUCCEEDED(hr) ? true : false; -} - -LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len) { - u8 *bytecode; - int bytecodelen; - if (CompileVertexShader(code, len, &bytecode, &bytecodelen)) { - LPDIRECT3DVERTEXSHADER9 v_shader = CreateVertexShaderFromByteCode(bytecode, len); - delete [] bytecode; - return v_shader; - } else { - return 0; - } -} - -LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len) { - u8 *bytecode; - int bytecodelen; - if (CompilePixelShader(code, len, &bytecode, &bytecodelen)) { - LPDIRECT3DPIXELSHADER9 p_shader = CreatePixelShaderFromByteCode(bytecode, len); - delete [] bytecode; - return p_shader; - } else { - return 0; - } -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include + +#include "VideoConfig.h" +#include "DX9_D3DShader.h" + +namespace DX9 +{ + +namespace D3D +{ + +// Bytecode->shader. +LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len) +{ + LPDIRECT3DVERTEXSHADER9 v_shader; + HRESULT hr = D3D::dev->CreateVertexShader((DWORD *)bytecode, &v_shader); + if (FAILED(hr)) + v_shader = 0; + return v_shader; +} + +// Code->bytecode. +bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen) +{ + //try to compile + LPD3DXBUFFER shaderBuffer = 0; + LPD3DXBUFFER errorBuffer = 0; + HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::VertexShaderVersionString(), + 0, &shaderBuffer, &errorBuffer, 0); + if (FAILED(hr)) + { + //compilation error + if (g_ActiveConfig.bShowShaderErrors) { + std::string hello = (char*)errorBuffer->GetBufferPointer(); + hello += "\n\n"; + hello += code; + MessageBoxA(0, hello.c_str(), "Error compiling vertex shader", MB_ICONERROR); + } + *bytecode = 0; + *bytecodelen = 0; + } + else if (SUCCEEDED(hr)) + { + *bytecodelen = shaderBuffer->GetBufferSize(); + *bytecode = new u8[*bytecodelen]; + memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen); + } + + //cleanup + if (shaderBuffer) + shaderBuffer->Release(); + if (errorBuffer) + errorBuffer->Release(); + return SUCCEEDED(hr) ? true : false; +} + + +// Bytecode->shader. +LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len) +{ + LPDIRECT3DPIXELSHADER9 p_shader; + HRESULT hr = D3D::dev->CreatePixelShader((DWORD *)bytecode, &p_shader); + if (FAILED(hr)) + p_shader = 0; + return p_shader; +} + + +bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen) +{ + LPD3DXBUFFER shaderBuffer = 0; + LPD3DXBUFFER errorBuffer = 0; + + // Someone: + // For some reason, I had this kind of errors : "Shader uses texture addressing operations + // in a dependency chain that is too complex for the target shader model (ps_2_0) to handle." + HRESULT hr = PD3DXCompileShader(code, len, 0, 0, "main", D3D::PixelShaderVersionString(), + 0, &shaderBuffer, &errorBuffer, 0); + + if (FAILED(hr)) + { + if (g_ActiveConfig.bShowShaderErrors) { + std::string hello = (char*)errorBuffer->GetBufferPointer(); + hello += "\n\n"; + hello += code; + MessageBoxA(0, hello.c_str(), "Error compiling pixel shader", MB_ICONERROR); + } + *bytecode = 0; + *bytecodelen = 0; + } + else if (SUCCEEDED(hr)) + { + *bytecodelen = shaderBuffer->GetBufferSize(); + *bytecode = new u8[*bytecodelen]; + memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen); + } + + //cleanup + if (shaderBuffer) + shaderBuffer->Release(); + if (errorBuffer) + errorBuffer->Release(); + return SUCCEEDED(hr) ? true : false; +} + +LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len) { + u8 *bytecode; + int bytecodelen; + if (CompileVertexShader(code, len, &bytecode, &bytecodelen)) { + LPDIRECT3DVERTEXSHADER9 v_shader = CreateVertexShaderFromByteCode(bytecode, len); + delete [] bytecode; + return v_shader; + } else { + return 0; + } +} + +LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len) { + u8 *bytecode; + int bytecodelen; + if (CompilePixelShader(code, len, &bytecode, &bytecodelen)) { + LPDIRECT3DPIXELSHADER9 p_shader = CreatePixelShaderFromByteCode(bytecode, len); + delete [] bytecode; + return p_shader; + } else { + return 0; + } +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.h index 262fd345ae..c36bd28ecc 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DShader.h @@ -1,39 +1,39 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "DX9_D3DBase.h" - -namespace DX9 -{ - -namespace D3D -{ - LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len); - LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len); - - // The returned bytecode buffers should be delete[]-d. - bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen); - bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen); - - // Utility functions - LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len); - LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "DX9_D3DBase.h" + +namespace DX9 +{ + +namespace D3D +{ + LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len); + LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len); + + // The returned bytecode buffers should be delete[]-d. + bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen); + bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen); + + // Utility functions + LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len); + LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.cpp index ad427ac9b6..29bc55a120 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.cpp @@ -1,275 +1,275 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DX9_D3DBase.h" -#include "DX9_D3DTexture.h" - -namespace DX9 -{ - -namespace D3D -{ - -LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int levels) -{ - u32* pBuffer = (u32*)buffer; - LPDIRECT3DTEXTURE9 pTexture; - - // crazy bitmagic, sorry :) - bool isPow2 = !((width&(width-1)) || (height&(height-1))); - bool bExpand = false; - - if (fmt == D3DFMT_A8P8) { - fmt = D3DFMT_A8L8; - bExpand = true; - } - - HRESULT hr; - // TODO(ector): Allow mipmaps for non-pow textures on newer cards? - // TODO(ector): Use the game-specified mipmaps? - if (levels > 0) - hr = dev->CreateTexture(width, height, levels, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); - else - hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL); - - if (FAILED(hr)) - return 0; - int level = 0; - D3DLOCKED_RECT Lock; - pTexture->LockRect(level, &Lock, NULL, 0); - switch (fmt) - { - case D3DFMT_L8: - case D3DFMT_A8: - case D3DFMT_A4L4: - { - const u8 *pIn = buffer; - for (int y = 0; y < height; y++) - { - u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width); - pIn += pitch; - } - } - break; - case D3DFMT_R5G6B5: - { - const u16 *pIn = (u16*)buffer; - for (int y = 0; y < height; y++) - { - u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 2); - pIn += pitch; - } - } - break; - case D3DFMT_A8L8: - { - if (bExpand) { // I8 - const u8 *pIn = buffer; - // TODO(XK): Find a better way that does not involve either unpacking - // or downsampling (i.e. A4L4) - for (int y = 0; y < height; y++) - { - u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); - for(int i = 0; i < width * 2; i += 2) { - pBits[i] = pIn[i / 2]; - pBits[i + 1] = pIn[i / 2]; - } - pIn += pitch; - } - } else { // IA8 - const u16 *pIn = (u16*)buffer; - - for (int y = 0; y < height; y++) - { - u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 2); - pIn += pitch; - } - } - } - break; - case D3DFMT_A8R8G8B8: - { - if(pitch * 4 == Lock.Pitch && !swap_r_b) - { - memcpy(Lock.pBits,buffer,Lock.Pitch*height); - } - else - { - u32* pIn = pBuffer; - if (!swap_r_b) { - for (int y = 0; y < height; y++) - { - u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 4); - pIn += pitch; - } - } else { - for (int y = 0; y < height; y++) - { - u8 *pIn8 = (u8 *)pIn; - u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch)); - for (int x = 0; x < width * 4; x += 4) { - pBits[x + 0] = pIn8[x + 2]; - pBits[x + 1] = pIn8[x + 1]; - pBits[x + 2] = pIn8[x + 0]; - pBits[x + 3] = pIn8[x + 3]; - } - pIn += pitch; - } - } - } - } - break; - case D3DFMT_DXT1: - memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8); - break; - default: - PanicAlert("D3D: Invalid texture format %i", fmt); - } - pTexture->UnlockRect(level); - return pTexture; -} - -LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt) -{ - LPDIRECT3DTEXTURE9 pTexture; - // crazy bitmagic, sorry :) - bool isPow2 = !((width&(width-1)) || (height&(height-1))); - bool bExpand = false; - HRESULT hr; - // TODO(ector): Allow mipmaps for non-pow textures on newer cards? - // TODO(ector): Use the game-specified mipmaps? - if (!isPow2) - hr = dev->CreateTexture(width, height, 1, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); - else - hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL); - - if (FAILED(hr)) - return 0; - return pTexture; -} - -void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level) -{ - u32* pBuffer = (u32*)buffer; - D3DLOCKED_RECT Lock; - pTexture->LockRect(level, &Lock, NULL, 0); - u32* pIn = pBuffer; - - bool bExpand = false; - - if (fmt == D3DFMT_A8P8) { - fmt = D3DFMT_A8L8; - bExpand = true; - } - switch (fmt) - { - case D3DFMT_A8R8G8B8: - if(pitch * 4 == Lock.Pitch && !swap_r_b) - { - memcpy(Lock.pBits, pBuffer, Lock.Pitch*height); - } - else if (!swap_r_b) - { - for (int y = 0; y < height; y++) - { - u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 4); - pIn += pitch; - } - } - else - { - for (int y = 0; y < height; y++) - { - u8 *pIn8 = (u8 *)pIn; - u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch)); - for (int x = 0; x < width * 4; x += 4) - { - pBits[x + 0] = pIn8[x + 2]; - pBits[x + 1] = pIn8[x + 1]; - pBits[x + 2] = pIn8[x + 0]; - pBits[x + 3] = pIn8[x + 3]; - } - pIn += pitch; - } - } - break; - case D3DFMT_L8: - case D3DFMT_A8: - case D3DFMT_A4L4: - { - const u8 *pIn = buffer; - for (int y = 0; y < height; y++) - { - u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width); - pIn += pitch; - } - } - break; - case D3DFMT_R5G6B5: - { - const u16 *pIn = (u16*)buffer; - for (int y = 0; y < height; y++) - { - u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 2); - pIn += pitch; - } - } - break; - case D3DFMT_A8L8: - { - if (bExpand) { // I8 - const u8 *pIn = buffer; - // TODO(XK): Find a better way that does not involve either unpacking - // or downsampling (i.e. A4L4) - for (int y = 0; y < height; y++) - { - u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); - for(int i = 0; i < width * 2; i += 2) { - pBits[i] = pIn[i / 2]; - pBits[i + 1] = pIn[i / 2]; - } - pIn += pitch; - } - } else { // IA8 - const u16 *pIn = (u16*)buffer; - - for (int y = 0; y < height; y++) - { - u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); - memcpy(pBits, pIn, width * 2); - pIn += pitch; - } - } - } - break; - case D3DFMT_DXT1: - memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8); - break; - } - pTexture->UnlockRect(level); -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DX9_D3DBase.h" +#include "DX9_D3DTexture.h" + +namespace DX9 +{ + +namespace D3D +{ + +LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int levels) +{ + u32* pBuffer = (u32*)buffer; + LPDIRECT3DTEXTURE9 pTexture; + + // crazy bitmagic, sorry :) + bool isPow2 = !((width&(width-1)) || (height&(height-1))); + bool bExpand = false; + + if (fmt == D3DFMT_A8P8) { + fmt = D3DFMT_A8L8; + bExpand = true; + } + + HRESULT hr; + // TODO(ector): Allow mipmaps for non-pow textures on newer cards? + // TODO(ector): Use the game-specified mipmaps? + if (levels > 0) + hr = dev->CreateTexture(width, height, levels, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); + else + hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL); + + if (FAILED(hr)) + return 0; + int level = 0; + D3DLOCKED_RECT Lock; + pTexture->LockRect(level, &Lock, NULL, 0); + switch (fmt) + { + case D3DFMT_L8: + case D3DFMT_A8: + case D3DFMT_A4L4: + { + const u8 *pIn = buffer; + for (int y = 0; y < height; y++) + { + u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width); + pIn += pitch; + } + } + break; + case D3DFMT_R5G6B5: + { + const u16 *pIn = (u16*)buffer; + for (int y = 0; y < height; y++) + { + u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 2); + pIn += pitch; + } + } + break; + case D3DFMT_A8L8: + { + if (bExpand) { // I8 + const u8 *pIn = buffer; + // TODO(XK): Find a better way that does not involve either unpacking + // or downsampling (i.e. A4L4) + for (int y = 0; y < height; y++) + { + u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); + for(int i = 0; i < width * 2; i += 2) { + pBits[i] = pIn[i / 2]; + pBits[i + 1] = pIn[i / 2]; + } + pIn += pitch; + } + } else { // IA8 + const u16 *pIn = (u16*)buffer; + + for (int y = 0; y < height; y++) + { + u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 2); + pIn += pitch; + } + } + } + break; + case D3DFMT_A8R8G8B8: + { + if(pitch * 4 == Lock.Pitch && !swap_r_b) + { + memcpy(Lock.pBits,buffer,Lock.Pitch*height); + } + else + { + u32* pIn = pBuffer; + if (!swap_r_b) { + for (int y = 0; y < height; y++) + { + u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 4); + pIn += pitch; + } + } else { + for (int y = 0; y < height; y++) + { + u8 *pIn8 = (u8 *)pIn; + u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch)); + for (int x = 0; x < width * 4; x += 4) { + pBits[x + 0] = pIn8[x + 2]; + pBits[x + 1] = pIn8[x + 1]; + pBits[x + 2] = pIn8[x + 0]; + pBits[x + 3] = pIn8[x + 3]; + } + pIn += pitch; + } + } + } + } + break; + case D3DFMT_DXT1: + memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8); + break; + default: + PanicAlert("D3D: Invalid texture format %i", fmt); + } + pTexture->UnlockRect(level); + return pTexture; +} + +LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt) +{ + LPDIRECT3DTEXTURE9 pTexture; + // crazy bitmagic, sorry :) + bool isPow2 = !((width&(width-1)) || (height&(height-1))); + bool bExpand = false; + HRESULT hr; + // TODO(ector): Allow mipmaps for non-pow textures on newer cards? + // TODO(ector): Use the game-specified mipmaps? + if (!isPow2) + hr = dev->CreateTexture(width, height, 1, 0, fmt, D3DPOOL_MANAGED, &pTexture, NULL); + else + hr = dev->CreateTexture(width, height, 0, D3DUSAGE_AUTOGENMIPMAP, fmt, D3DPOOL_MANAGED, &pTexture, NULL); + + if (FAILED(hr)) + return 0; + return pTexture; +} + +void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level) +{ + u32* pBuffer = (u32*)buffer; + D3DLOCKED_RECT Lock; + pTexture->LockRect(level, &Lock, NULL, 0); + u32* pIn = pBuffer; + + bool bExpand = false; + + if (fmt == D3DFMT_A8P8) { + fmt = D3DFMT_A8L8; + bExpand = true; + } + switch (fmt) + { + case D3DFMT_A8R8G8B8: + if(pitch * 4 == Lock.Pitch && !swap_r_b) + { + memcpy(Lock.pBits, pBuffer, Lock.Pitch*height); + } + else if (!swap_r_b) + { + for (int y = 0; y < height; y++) + { + u32 *pBits = (u32*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 4); + pIn += pitch; + } + } + else + { + for (int y = 0; y < height; y++) + { + u8 *pIn8 = (u8 *)pIn; + u8 *pBits = (u8 *)((u8*)Lock.pBits + (y * Lock.Pitch)); + for (int x = 0; x < width * 4; x += 4) + { + pBits[x + 0] = pIn8[x + 2]; + pBits[x + 1] = pIn8[x + 1]; + pBits[x + 2] = pIn8[x + 0]; + pBits[x + 3] = pIn8[x + 3]; + } + pIn += pitch; + } + } + break; + case D3DFMT_L8: + case D3DFMT_A8: + case D3DFMT_A4L4: + { + const u8 *pIn = buffer; + for (int y = 0; y < height; y++) + { + u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width); + pIn += pitch; + } + } + break; + case D3DFMT_R5G6B5: + { + const u16 *pIn = (u16*)buffer; + for (int y = 0; y < height; y++) + { + u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 2); + pIn += pitch; + } + } + break; + case D3DFMT_A8L8: + { + if (bExpand) { // I8 + const u8 *pIn = buffer; + // TODO(XK): Find a better way that does not involve either unpacking + // or downsampling (i.e. A4L4) + for (int y = 0; y < height; y++) + { + u8* pBits = ((u8*)Lock.pBits + (y * Lock.Pitch)); + for(int i = 0; i < width * 2; i += 2) { + pBits[i] = pIn[i / 2]; + pBits[i + 1] = pIn[i / 2]; + } + pIn += pitch; + } + } else { // IA8 + const u16 *pIn = (u16*)buffer; + + for (int y = 0; y < height; y++) + { + u16* pBits = (u16*)((u8*)Lock.pBits + (y * Lock.Pitch)); + memcpy(pBits, pIn, width * 2); + pIn += pitch; + } + } + } + break; + case D3DFMT_DXT1: + memcpy(Lock.pBits,buffer,((width+3)/4)*((height+3)/4)*8); + break; + } + pTexture->UnlockRect(level); +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.h index 46652a4964..cbad1a870f 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DTexture.h @@ -1,34 +1,34 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "DX9_D3DBase.h" - -namespace DX9 -{ - -namespace D3D -{ - LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt = D3DFMT_A8R8G8B8, bool swap_r_b = false, int levels = 1); - void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level = 0); - LPDIRECT3DTEXTURE9 CreateRenderTarget(const int width, const int height); - LPDIRECT3DSURFACE9 CreateDepthStencilSurface(const int width, const int height); - LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "DX9_D3DBase.h" + +namespace DX9 +{ + +namespace D3D +{ + LPDIRECT3DTEXTURE9 CreateTexture2D(const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt = D3DFMT_A8R8G8B8, bool swap_r_b = false, int levels = 1); + void ReplaceTexture2D(LPDIRECT3DTEXTURE9 pTexture, const u8* buffer, const int width, const int height, const int pitch, D3DFORMAT fmt, bool swap_r_b, int level = 0); + LPDIRECT3DTEXTURE9 CreateRenderTarget(const int width, const int height); + LPDIRECT3DSURFACE9 CreateDepthStencilSurface(const int width, const int height); + LPDIRECT3DTEXTURE9 CreateOnlyTexture2D(const int width, const int height, D3DFORMAT fmt); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.cpp index 9974fce776..b172f00f40 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.cpp @@ -1,447 +1,447 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "Common.h" -#include "StringUtil.h" - -#include "DX9_D3DBase.h" -#include "DX9_D3DUtil.h" -#include "DX9_Render.h" - -namespace DX9 -{ - -namespace D3D -{ - -CD3DFont font; - -#define MAX_NUM_VERTICES 50*6 -struct FONT2DVERTEX { - float x,y,z; - float rhw; - u32 color; - float tu, tv; -}; - -#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) -#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX1) - -inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) -{ - FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv; - return v; -} - -CD3DFont::CD3DFont() -{ - m_pTexture = NULL; - m_pVB = NULL; -} - -enum {m_dwTexWidth = 512, m_dwTexHeight = 512}; - -int CD3DFont::Init() -{ - // Create vertex buffer for the letters - HRESULT hr; - if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), - D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL))) - { - return hr; - } - m_fTextScale = 1.0f; // Draw fonts into texture without scaling - - // Prepare to create a bitmap - int *pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(NULL); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0); - SetMapMode(hDC, MM_TEXT); - - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - // We definitely don't want to get it cleartype'd, anyway. - int m_dwFontHeight = 24; - int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72); - int dwBold = FW_NORMAL; ///FW_BOLD - HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, _T("Tahoma")); - if (NULL == hFont) - return E_FAIL; - - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); - - // Set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor (hDC, 0); - SetTextAlign(hDC, TA_TOP); - - // Loop through all printable character and output them to the bitmap.. - // Meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if ((int)(x+size.cx+1) > m_dwTexWidth) - { - x = 0; - y += size.cy + 1; - } - - ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); - m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth; - m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight; - m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth; - m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight; - - x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i) - } - - // Create a new texture for the font - hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC, - D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL); - if (FAILED(hr)) - { - PanicAlert("Failed to create font texture"); - return hr; - } - - // Lock the surface and write the alpha values for the set pixels - D3DLOCKED_RECT d3dlr; - m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD); - int bAlpha; // 4-bit measure of pixel intensity - - for (y = 0; y < m_dwTexHeight; y++) - { - u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch); - for (x = 0; x < m_dwTexWidth; x++) - { - bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); - pDst16[x] = (bAlpha << 12) | 0x0fff; - } - } - - // Done updating texture, so clean up used objects - m_pTexture->UnlockRect(0); - - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); - - SelectObject(hDC, hOldFont); - DeleteObject(hFont); - - return S_OK; -} - -int CD3DFont::Shutdown() -{ - m_pVB->Release(); - m_pVB = NULL; - m_pTexture->Release(); - m_pTexture = NULL; - return S_OK; -} - - -const int RS[6][2] = -{ - {D3DRS_ALPHABLENDENABLE, TRUE}, - {D3DRS_SRCBLEND, D3DBLEND_SRCALPHA}, - {D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA}, - {D3DRS_CULLMODE, D3DCULL_NONE}, - {D3DRS_ZENABLE, FALSE}, - {D3DRS_FOGENABLE, FALSE}, -}; -const int TS[6][2] = -{ - {D3DTSS_COLOROP, D3DTOP_MODULATE}, - {D3DTSS_COLORARG1, D3DTA_TEXTURE}, - {D3DTSS_COLORARG2, D3DTA_DIFFUSE }, - {D3DTSS_ALPHAOP, D3DTOP_MODULATE }, - {D3DTSS_ALPHAARG1, D3DTA_TEXTURE }, - {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE }, -}; - -static LPDIRECT3DPIXELSHADER9 ps_old = NULL; -static LPDIRECT3DVERTEXSHADER9 vs_old = NULL; - -void RestoreShaders() -{ - D3D::SetTexture(0, 0); - D3D::RefreshVertexDeclaration(); - D3D::RefreshPixelShader(); - D3D::RefreshVertexShader(); -} - -void RestoreRenderStates() -{ - RestoreShaders(); - for (int i = 0; i < 6; i++) - { - D3D::RefreshRenderState((_D3DRENDERSTATETYPE)RS[i][0]); - D3D::RefreshTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0])); - } -} - -void CD3DFont::SetRenderStates() -{ - D3D::SetTexture(0, m_pTexture); - - dev->SetPixelShader(0); - dev->SetVertexShader(0); - - dev->SetFVF(D3DFVF_FONT2DVERTEX); - - for (int i = 0; i < 6; i++) - { - D3D::ChangeRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]); - D3D::ChangeTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]); - } -} - - -int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center) -{ - if (!m_pVB) - return 0; - - SetRenderStates(); - dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); - - float vpWidth = 1; - float vpHeight = 1; - - float sx = x*vpWidth-0.5f; - float sy = y*vpHeight-0.5f; - - float fStartX = sx; - - float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); - // Fill vertex buffer - FONT2DVERTEX* pVertices; - int dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - const char *oldstrText=strText; - //First, let's measure the text - float tw=0; - float mx=0; - float maxx=0; - - while (*strText) - { - char c = *strText++; - - if (c == ('\n')) - mx = 0; - if (c < (' ')) - continue; - - float tx1 = m_fTexCoords[c-32][0]; - float tx2 = m_fTexCoords[c-32][2]; - - float w = (tx2-tx1)*m_dwTexWidth; - w *= (fXScale*vpHeight)*invLineHeight; - mx += w + spacing*fXScale*vpWidth; - if (mx > maxx) maxx = mx; - } - - float offset = -maxx/2; - strText = oldstrText; - //Then let's draw it - if (center) - { - sx+=offset; - fStartX+=offset; - } - - float wScale = (fXScale*vpHeight)*invLineHeight; - float hScale = (fYScale*vpHeight)*invLineHeight; - - while (*strText) - { - char c = *strText++; - - if (c == ('\n')) - { - sx = fStartX; - sy += fYScale*vpHeight; - } - if (c < (' ')) - continue; - - c-=32; - float tx1 = m_fTexCoords[c][0]; - float ty1 = m_fTexCoords[c][1]; - float tx2 = m_fTexCoords[c][2]; - float ty2 = m_fTexCoords[c][3]; - - float w = (tx2-tx1)*m_dwTexWidth; - float h = (ty2-ty1)*m_dwTexHeight; - - w *= wScale; - h *= hScale; - - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2); - v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; - - memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); - - pVertices+=6; - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) - { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0; - } - - sx += w + spacing*fXScale*vpWidth; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) - dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - RestoreRenderStates(); - return S_OK; -} - -void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2) -{ - struct Q2DVertex { float x,y,z,rhw;u32 color;float u,v,w,h; } coords[4] = { - {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1}, - {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1}, - {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2}, - {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2}, - }; - dev->SetPixelShader(0); - dev->SetVertexShader(0); - dev->SetVertexDeclaration(NULL); - dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); - dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); - RestoreShaders(); -} - -void drawShadedTexQuad(IDirect3DTexture9 *texture, - const RECT *rSource, - int SourceWidth, - int SourceHeight, - int DestWidth, - int DestHeight, - IDirect3DPixelShader9 *PShader, - IDirect3DVertexShader9 *Vshader) -{ - float sw = 1.0f /(float) SourceWidth; - float sh = 1.0f /(float) SourceHeight; - float dw = 1.0f /(float) DestWidth; - float dh = 1.0f /(float) DestHeight; - float u1=((float)rSource->left) * sw; - float u2=((float)rSource->right) * sw; - float v1=((float)rSource->top) * sh; - float v2=((float)rSource->bottom) * sh; - - struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = { - {-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2}, - {-1.0f - dw, 1.0f + dh, 0.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2}, - { 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2}, - { 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2} - }; - dev->SetVertexShader(Vshader); - dev->SetPixelShader(PShader); - D3D::SetTexture(0, texture); - dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2)); - dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex)); - RestoreShaders(); -} - -void drawShadedTexSubQuad(IDirect3DTexture9 *texture, - const MathUtil::Rectangle *rSource, - int SourceWidth, - int SourceHeight, - const MathUtil::Rectangle *rDest, - int DestWidth, - int DestHeight, - IDirect3DPixelShader9 *PShader, - IDirect3DVertexShader9 *Vshader) -{ - float sw = 1.0f /(float) SourceWidth; - float sh = 1.0f /(float) SourceHeight; - float dw = 1.0f /(float) DestWidth; - float dh = 1.0f /(float) DestHeight; - float u1= rSource->left * sw; - float u2= rSource->right * sw; - float v1= rSource->top * sh; - float v2= rSource->bottom * sh; - - struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = { - { rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2}, - { rDest->left - dw , rDest->bottom + dh, 1.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2}, - { rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2}, - { rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2} - }; - dev->SetVertexShader(Vshader); - dev->SetPixelShader(PShader); - D3D::SetTexture(0, texture); - dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2)); - dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex)); - RestoreShaders(); -} - -void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader) -{ - struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = { - {-1.0f, 1.0f, z, 1.0f, Color}, - { 1.0f, 1.0f, z, 1.0f, Color}, - { 1.0f, -1.0f, z, 1.0f, Color}, - {-1.0f, -1.0f, z, 1.0f, Color} - }; - dev->SetVertexShader(Vshader); - dev->SetPixelShader(PShader); - dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE); - dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); - RestoreShaders(); -} - - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "StringUtil.h" + +#include "DX9_D3DBase.h" +#include "DX9_D3DUtil.h" +#include "DX9_Render.h" + +namespace DX9 +{ + +namespace D3D +{ + +CD3DFont font; + +#define MAX_NUM_VERTICES 50*6 +struct FONT2DVERTEX { + float x,y,z; + float rhw; + u32 color; + float tu, tv; +}; + +#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) +#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX1) + +inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) +{ + FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv; + return v; +} + +CD3DFont::CD3DFont() +{ + m_pTexture = NULL; + m_pVB = NULL; +} + +enum {m_dwTexWidth = 512, m_dwTexHeight = 512}; + +int CD3DFont::Init() +{ + // Create vertex buffer for the letters + HRESULT hr; + if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), + D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL))) + { + return hr; + } + m_fTextScale = 1.0f; // Draw fonts into texture without scaling + + // Prepare to create a bitmap + int *pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + // Create a DC and a bitmap for the font + HDC hDC = CreateCompatibleDC(NULL); + HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0); + SetMapMode(hDC, MM_TEXT); + + // Create a font. By specifying ANTIALIASED_QUALITY, we might get an + // antialiased font, but this is not guaranteed. + // We definitely don't want to get it cleartype'd, anyway. + int m_dwFontHeight = 24; + int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72); + int dwBold = FW_NORMAL; ///FW_BOLD + HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0, + FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, + VARIABLE_PITCH, _T("Tahoma")); + if (NULL == hFont) + return E_FAIL; + + HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); + HGDIOBJ hOldFont = SelectObject(hDC, hFont); + + // Set text properties + SetTextColor(hDC, 0xFFFFFF); + SetBkColor (hDC, 0); + SetTextAlign(hDC, TA_TOP); + + // Loop through all printable character and output them to the bitmap.. + // Meanwhile, keep track of the corresponding tex coords for each character. + int x = 0, y = 0; + char str[2] = "\0"; + for (int c = 0; c < 127 - 32; c++) + { + str[0] = c + 32; + SIZE size; + GetTextExtentPoint32A(hDC, str, 1, &size); + if ((int)(x+size.cx+1) > m_dwTexWidth) + { + x = 0; + y += size.cy + 1; + } + + ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); + m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth; + m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight; + m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth; + m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight; + + x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i) + } + + // Create a new texture for the font + hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC, + D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL); + if (FAILED(hr)) + { + PanicAlert("Failed to create font texture"); + return hr; + } + + // Lock the surface and write the alpha values for the set pixels + D3DLOCKED_RECT d3dlr; + m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD); + int bAlpha; // 4-bit measure of pixel intensity + + for (y = 0; y < m_dwTexHeight; y++) + { + u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch); + for (x = 0; x < m_dwTexWidth; x++) + { + bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); + pDst16[x] = (bAlpha << 12) | 0x0fff; + } + } + + // Done updating texture, so clean up used objects + m_pTexture->UnlockRect(0); + + SelectObject(hDC, hOldbmBitmap); + DeleteObject(hbmBitmap); + + SelectObject(hDC, hOldFont); + DeleteObject(hFont); + + return S_OK; +} + +int CD3DFont::Shutdown() +{ + m_pVB->Release(); + m_pVB = NULL; + m_pTexture->Release(); + m_pTexture = NULL; + return S_OK; +} + + +const int RS[6][2] = +{ + {D3DRS_ALPHABLENDENABLE, TRUE}, + {D3DRS_SRCBLEND, D3DBLEND_SRCALPHA}, + {D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA}, + {D3DRS_CULLMODE, D3DCULL_NONE}, + {D3DRS_ZENABLE, FALSE}, + {D3DRS_FOGENABLE, FALSE}, +}; +const int TS[6][2] = +{ + {D3DTSS_COLOROP, D3DTOP_MODULATE}, + {D3DTSS_COLORARG1, D3DTA_TEXTURE}, + {D3DTSS_COLORARG2, D3DTA_DIFFUSE }, + {D3DTSS_ALPHAOP, D3DTOP_MODULATE }, + {D3DTSS_ALPHAARG1, D3DTA_TEXTURE }, + {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE }, +}; + +static LPDIRECT3DPIXELSHADER9 ps_old = NULL; +static LPDIRECT3DVERTEXSHADER9 vs_old = NULL; + +void RestoreShaders() +{ + D3D::SetTexture(0, 0); + D3D::RefreshVertexDeclaration(); + D3D::RefreshPixelShader(); + D3D::RefreshVertexShader(); +} + +void RestoreRenderStates() +{ + RestoreShaders(); + for (int i = 0; i < 6; i++) + { + D3D::RefreshRenderState((_D3DRENDERSTATETYPE)RS[i][0]); + D3D::RefreshTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0])); + } +} + +void CD3DFont::SetRenderStates() +{ + D3D::SetTexture(0, m_pTexture); + + dev->SetPixelShader(0); + dev->SetVertexShader(0); + + dev->SetFVF(D3DFVF_FONT2DVERTEX); + + for (int i = 0; i < 6; i++) + { + D3D::ChangeRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]); + D3D::ChangeTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]); + } +} + + +int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center) +{ + if (!m_pVB) + return 0; + + SetRenderStates(); + dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + float vpWidth = 1; + float vpHeight = 1; + + float sx = x*vpWidth-0.5f; + float sy = y*vpHeight-0.5f; + + float fStartX = sx; + + float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); + // Fill vertex buffer + FONT2DVERTEX* pVertices; + int dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + const char *oldstrText=strText; + //First, let's measure the text + float tw=0; + float mx=0; + float maxx=0; + + while (*strText) + { + char c = *strText++; + + if (c == ('\n')) + mx = 0; + if (c < (' ')) + continue; + + float tx1 = m_fTexCoords[c-32][0]; + float tx2 = m_fTexCoords[c-32][2]; + + float w = (tx2-tx1)*m_dwTexWidth; + w *= (fXScale*vpHeight)*invLineHeight; + mx += w + spacing*fXScale*vpWidth; + if (mx > maxx) maxx = mx; + } + + float offset = -maxx/2; + strText = oldstrText; + //Then let's draw it + if (center) + { + sx+=offset; + fStartX+=offset; + } + + float wScale = (fXScale*vpHeight)*invLineHeight; + float hScale = (fYScale*vpHeight)*invLineHeight; + + while (*strText) + { + char c = *strText++; + + if (c == ('\n')) + { + sx = fStartX; + sy += fYScale*vpHeight; + } + if (c < (' ')) + continue; + + c-=32; + float tx1 = m_fTexCoords[c][0]; + float ty1 = m_fTexCoords[c][1]; + float tx2 = m_fTexCoords[c][2]; + float ty2 = m_fTexCoords[c][3]; + + float w = (tx2-tx1)*m_dwTexWidth; + float h = (ty2-ty1)*m_dwTexHeight; + + w *= wScale; + h *= hScale; + + FONT2DVERTEX v[6]; + v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2); + v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); + v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2); + v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1); + v[4] = v[2]; + v[5] = v[1]; + + memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); + + pVertices+=6; + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) + { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0; + } + + sx += w + spacing*fXScale*vpWidth; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) + dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + RestoreRenderStates(); + return S_OK; +} + +void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2) +{ + struct Q2DVertex { float x,y,z,rhw;u32 color;float u,v,w,h; } coords[4] = { + {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1}, + {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1}, + {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2}, + {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2}, + }; + dev->SetPixelShader(0); + dev->SetVertexShader(0); + dev->SetVertexDeclaration(NULL); + dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); + RestoreShaders(); +} + +void drawShadedTexQuad(IDirect3DTexture9 *texture, + const RECT *rSource, + int SourceWidth, + int SourceHeight, + int DestWidth, + int DestHeight, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader) +{ + float sw = 1.0f /(float) SourceWidth; + float sh = 1.0f /(float) SourceHeight; + float dw = 1.0f /(float) DestWidth; + float dh = 1.0f /(float) DestHeight; + float u1=((float)rSource->left) * sw; + float u2=((float)rSource->right) * sw; + float v1=((float)rSource->top) * sh; + float v2=((float)rSource->bottom) * sh; + + struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = { + {-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2}, + {-1.0f - dw, 1.0f + dh, 0.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2}, + { 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2}, + { 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2} + }; + dev->SetVertexShader(Vshader); + dev->SetPixelShader(PShader); + D3D::SetTexture(0, texture); + dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2)); + dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex)); + RestoreShaders(); +} + +void drawShadedTexSubQuad(IDirect3DTexture9 *texture, + const MathUtil::Rectangle *rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle *rDest, + int DestWidth, + int DestHeight, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader) +{ + float sw = 1.0f /(float) SourceWidth; + float sh = 1.0f /(float) SourceHeight; + float dw = 1.0f /(float) DestWidth; + float dh = 1.0f /(float) DestHeight; + float u1= rSource->left * sw; + float u2= rSource->right * sw; + float v1= rSource->top * sh; + float v2= rSource->bottom * sh; + + struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = { + { rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2}, + { rDest->left - dw , rDest->bottom + dh, 1.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2}, + { rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2}, + { rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2} + }; + dev->SetVertexShader(Vshader); + dev->SetPixelShader(PShader); + D3D::SetTexture(0, texture); + dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2)); + dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex)); + RestoreShaders(); +} + +void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader) +{ + struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = { + {-1.0f, 1.0f, z, 1.0f, Color}, + { 1.0f, 1.0f, z, 1.0f, Color}, + { 1.0f, -1.0f, z, 1.0f, Color}, + {-1.0f, -1.0f, z, 1.0f, Color} + }; + dev->SetVertexShader(Vshader); + dev->SetPixelShader(PShader); + dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE); + dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); + RestoreShaders(); +} + + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.h index 4beeb1ea27..74fd64217a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_D3DUtil.h @@ -1,88 +1,88 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#pragma once - -#include "DX9_D3DBase.h" -#include -#include - -namespace DX9 -{ - -namespace D3D -{ - // Font creation flags - #define D3DFONT_BOLD 0x0001 - #define D3DFONT_ITALIC 0x0002 - - // Font rendering flags - #define D3DFONT_CENTERED 0x0001 - - //a cut-down variant of the DXSDK CD3DFont class - class CD3DFont - { - LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font - LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text - //int m_dwTexWidth; // Texture dimensions - //int m_dwTexHeight; - float m_fTextScale; - float m_fTexCoords[128-32][4]; - - public: - CD3DFont(); - // 2D (no longer 3D) text drawing function - // Initializing and destroying device-dependent objects - void SetRenderStates(); - int Init(); - int Shutdown(); - int DrawTextScaled( float x, float y, - float fXScale, float fYScale, - float spacing, u32 dwColor, - const char* strText, bool center=true ); - - - // Constructor / destructor - //~CD3DFont(); - }; - - extern CD3DFont font; - - void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1=0, float v1=0, float u2=1, float v2=1); - void drawShadedTexQuad(IDirect3DTexture9 *texture, - const RECT *rSource, - int SourceWidth, - int SourceHeight, - int DestWidth, - int DestHeight, - IDirect3DPixelShader9 *PShader, - IDirect3DVertexShader9 *Vshader); - void drawShadedTexSubQuad(IDirect3DTexture9 *texture, - const MathUtil::Rectangle *rSource, - int SourceWidth, - int SourceHeight, - const MathUtil::Rectangle *rDest, - int DestWidth, - int DestHeight, - IDirect3DPixelShader9 *PShader, - IDirect3DVertexShader9 *Vshader); - void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader); - void SaveRenderStates(); - void RestoreRenderStates(); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#pragma once + +#include "DX9_D3DBase.h" +#include +#include + +namespace DX9 +{ + +namespace D3D +{ + // Font creation flags + #define D3DFONT_BOLD 0x0001 + #define D3DFONT_ITALIC 0x0002 + + // Font rendering flags + #define D3DFONT_CENTERED 0x0001 + + //a cut-down variant of the DXSDK CD3DFont class + class CD3DFont + { + LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font + LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text + //int m_dwTexWidth; // Texture dimensions + //int m_dwTexHeight; + float m_fTextScale; + float m_fTexCoords[128-32][4]; + + public: + CD3DFont(); + // 2D (no longer 3D) text drawing function + // Initializing and destroying device-dependent objects + void SetRenderStates(); + int Init(); + int Shutdown(); + int DrawTextScaled( float x, float y, + float fXScale, float fYScale, + float spacing, u32 dwColor, + const char* strText, bool center=true ); + + + // Constructor / destructor + //~CD3DFont(); + }; + + extern CD3DFont font; + + void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1=0, float v1=0, float u2=1, float v2=1); + void drawShadedTexQuad(IDirect3DTexture9 *texture, + const RECT *rSource, + int SourceWidth, + int SourceHeight, + int DestWidth, + int DestHeight, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader); + void drawShadedTexSubQuad(IDirect3DTexture9 *texture, + const MathUtil::Rectangle *rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle *rDest, + int DestWidth, + int DestHeight, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader); + void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader); + void SaveRenderStates(); + void RestoreRenderStates(); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.cpp index 485be8c4d3..2c284de3e6 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.cpp @@ -1,285 +1,285 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DX9_D3DBase.h" -#include "DX9_Render.h" -#include "DX9_FramebufferManager.h" -#include "VideoConfig.h" -#include "DX9_PixelShaderCache.h" -#include "DX9_VertexShaderCache.h" -#include "DX9_TextureConverter.h" - -#include "../Main.h" - -#undef CHECK -#define CHECK(hr, Message, ...) if (FAILED(hr)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } - -namespace DX9 -{ - -XFBSource FramebufferManager::m_realXFBSource; - -LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_color_texture; -LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_colorRead_texture; -LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depth_texture; -LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depthRead_texture; - -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_surface; -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_surface; -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_ReadBuffer; -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_ReadBuffer; -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_OffScreenReadBuffer; -LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_OffScreenReadBuffer; - -D3DFORMAT FramebufferManager::s_efb_color_surface_Format; -D3DFORMAT FramebufferManager::s_efb_depth_surface_Format; -D3DFORMAT FramebufferManager::s_efb_depth_ReadBuffer_Format; - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorRTSurface() -{ - return s_efb_color_surface; -} - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthRTSurface() -{ - return s_efb_depth_surface; -} - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorOffScreenRTSurface() -{ - return s_efb_color_OffScreenReadBuffer; -} - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthOffScreenRTSurface() -{ - return s_efb_depth_OffScreenReadBuffer; -} - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorReadSurface() -{ - return s_efb_color_ReadBuffer; -} - -LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthReadSurface() -{ - return s_efb_depth_ReadBuffer; -} - -D3DFORMAT FramebufferManager::GetEFBDepthRTSurfaceFormat() -{ - return s_efb_depth_surface_Format; -} - -D3DFORMAT FramebufferManager::GetEFBDepthReadSurfaceFormat() -{ - return s_efb_depth_ReadBuffer_Format; -} - -D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat() -{ - return s_efb_color_surface_Format; -} - -LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) -{ - return s_efb_color_texture; -} - -LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc) -{ - return s_efb_depth_texture; -} - -FramebufferManager::FramebufferManager() -{ - s_efb_color_texture = NULL; - LPDIRECT3DTEXTURE9 s_efb_colorRead_texture = NULL; - LPDIRECT3DTEXTURE9 s_efb_depth_texture = NULL; - LPDIRECT3DTEXTURE9 s_efb_depthRead_texture = NULL; - - LPDIRECT3DSURFACE9 s_efb_depth_surface = NULL; - LPDIRECT3DSURFACE9 s_efb_color_surface = NULL; - LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer = NULL; - LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer = NULL; - LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer = NULL; - LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer = NULL; - - D3DFORMAT s_efb_color_surface_Format = D3DFMT_FORCE_DWORD; - D3DFORMAT s_efb_depth_surface_Format = D3DFMT_FORCE_DWORD; - D3DFORMAT s_efb_depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD; - m_realXFBSource.texture = NULL; - - // Simplest possible setup to start with. - int target_width = Renderer::GetFullTargetWidth(); - int target_height = Renderer::GetFullTargetHeight(); - - s_efb_color_surface_Format = D3DFMT_A8R8G8B8; - // Get the framebuffer texture - HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, - D3DPOOL_DEFAULT, &s_efb_color_texture, NULL); - if(s_efb_color_texture) - { - hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface); - } - CHECK(hr, "Create color texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); - hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, - D3DPOOL_DEFAULT, &s_efb_colorRead_texture, NULL); - CHECK(hr, "Create Color Read Texture (hr=%#x)", hr); - if(s_efb_colorRead_texture) - { - s_efb_colorRead_texture->GetSurfaceLevel(0, &s_efb_color_ReadBuffer); - } - // Create an offscreen surface that we can lock to retrieve the data - hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_color_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL); - CHECK(hr, "Create offscreen color surface (hr=%#x)", hr); - - // Select a Z-buffer format with hardware support - D3DFORMAT *DepthTexFormats = new D3DFORMAT[5]; - DepthTexFormats[0] = FOURCC_INTZ; - DepthTexFormats[1] = FOURCC_DF24; - DepthTexFormats[2] = FOURCC_RAWZ; - DepthTexFormats[3] = FOURCC_DF16; - DepthTexFormats[4] = D3DFMT_D24X8; - - for(int i = 0; i < 5; i++) - { - s_efb_depth_surface_Format = DepthTexFormats[i]; - // Create the framebuffer depth texture - hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format, - D3DPOOL_DEFAULT, &s_efb_depth_texture, NULL); - if (!FAILED(hr)) - break; - } - CHECK(hr, "Framebuffer depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); - // Get the Surface - if(s_efb_depth_texture) - { - s_efb_depth_texture->GetSurfaceLevel(0, &s_efb_depth_surface); - } - // Create a 4x4 pixel texture to work as a buffer for peeking - if(s_efb_depth_surface_Format == FOURCC_RAWZ || s_efb_depth_surface_Format == D3DFMT_D24X8) - { - DepthTexFormats[0] = D3DFMT_A8R8G8B8; - } - else - { - DepthTexFormats[0] = D3DFMT_R32F; - } - DepthTexFormats[1] = D3DFMT_A8R8G8B8; - - for(int i = 0; i < 2; i++) - { - s_efb_depth_ReadBuffer_Format = DepthTexFormats[i]; - // Get the framebuffer Depth texture - hr = D3D::dev->CreateTexture(4, 4, 1, D3DUSAGE_RENDERTARGET, s_efb_depth_ReadBuffer_Format, - D3DPOOL_DEFAULT, &s_efb_depthRead_texture, NULL); - if (!FAILED(hr)) - break; - } - - CHECK(hr, "Create depth read texture (hr=%#x)", hr); - if(s_efb_depthRead_texture) - { - s_efb_depthRead_texture->GetSurfaceLevel(0, &s_efb_depth_ReadBuffer); - } - // Create an offscreen surface that we can lock to retrieve the data - hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb_depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL); - CHECK(hr, "Create depth offscreen surface (hr=%#x)", hr); - delete [] DepthTexFormats; -} - -FramebufferManager::~FramebufferManager() -{ - SAFE_RELEASE(s_efb_depth_surface); - SAFE_RELEASE(s_efb_color_surface); - SAFE_RELEASE(s_efb_color_ReadBuffer); - SAFE_RELEASE(s_efb_depth_ReadBuffer); - SAFE_RELEASE(s_efb_color_OffScreenReadBuffer); - SAFE_RELEASE(s_efb_depth_OffScreenReadBuffer); - SAFE_RELEASE(s_efb_color_texture); - SAFE_RELEASE(s_efb_colorRead_texture); - SAFE_RELEASE(s_efb_depth_texture); - SAFE_RELEASE(s_efb_depthRead_texture); - - if (m_realXFBSource.texture) - m_realXFBSource.texture->Release(); - m_realXFBSource.texture = NULL; -} - -void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - // TODO: - - //u8* xfb_in_ram = Memory_GetPtr(xfbAddr); - //if (!xfb_in_ram) - //{ - // WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - // return; - //} - - //TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); - //TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight); -} - -const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) -{ - return NULL; - - // TODO: - //xfbCount = 1; - - //m_realXFBSource.texWidth = fbWidth; - //m_realXFBSource.texHeight = fbHeight; - - //m_realXFBSource.srcAddr = xfbAddr; - //m_realXFBSource.srcWidth = fbWidth; - //m_realXFBSource.srcHeight = fbHeight; - - //if (!m_realXFBSource.texture) - //{ - // D3D::dev->CreateTexture(fbWidth, fbHeight, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, - // D3DPOOL_DEFAULT, &m_realXFBSource.texture, NULL); - //} - - //// Decode YUYV data from GameCube RAM - //TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); - - //m_overlappingXFBArray[0] = &m_realXFBSource; - - //return &m_overlappingXFBArray[0]; -} - -XFBSourceBase *FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) -{ - XFBSource* const xfbs = new XFBSource; - D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, - D3DPOOL_DEFAULT, &xfbs->texture, NULL); - - return xfbs; -} - -XFBSource::~XFBSource() -{ - texture->Release(); -} - -void XFBSource::CopyEFB(const TargetRectangle& efbSource) -{ - -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DX9_D3DBase.h" +#include "DX9_Render.h" +#include "DX9_FramebufferManager.h" +#include "VideoConfig.h" +#include "DX9_PixelShaderCache.h" +#include "DX9_VertexShaderCache.h" +#include "DX9_TextureConverter.h" + +#include "../Main.h" + +#undef CHECK +#define CHECK(hr, Message, ...) if (FAILED(hr)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); } + +namespace DX9 +{ + +XFBSource FramebufferManager::m_realXFBSource; + +LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_color_texture; +LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_colorRead_texture; +LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depth_texture; +LPDIRECT3DTEXTURE9 FramebufferManager::s_efb_depthRead_texture; + +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_surface; +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_surface; +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_ReadBuffer; +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_ReadBuffer; +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_color_OffScreenReadBuffer; +LPDIRECT3DSURFACE9 FramebufferManager::s_efb_depth_OffScreenReadBuffer; + +D3DFORMAT FramebufferManager::s_efb_color_surface_Format; +D3DFORMAT FramebufferManager::s_efb_depth_surface_Format; +D3DFORMAT FramebufferManager::s_efb_depth_ReadBuffer_Format; + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorRTSurface() +{ + return s_efb_color_surface; +} + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthRTSurface() +{ + return s_efb_depth_surface; +} + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorOffScreenRTSurface() +{ + return s_efb_color_OffScreenReadBuffer; +} + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthOffScreenRTSurface() +{ + return s_efb_depth_OffScreenReadBuffer; +} + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorReadSurface() +{ + return s_efb_color_ReadBuffer; +} + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthReadSurface() +{ + return s_efb_depth_ReadBuffer; +} + +D3DFORMAT FramebufferManager::GetEFBDepthRTSurfaceFormat() +{ + return s_efb_depth_surface_Format; +} + +D3DFORMAT FramebufferManager::GetEFBDepthReadSurfaceFormat() +{ + return s_efb_depth_ReadBuffer_Format; +} + +D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat() +{ + return s_efb_color_surface_Format; +} + +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) +{ + return s_efb_color_texture; +} + +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc) +{ + return s_efb_depth_texture; +} + +FramebufferManager::FramebufferManager() +{ + s_efb_color_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_colorRead_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_depth_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_depthRead_texture = NULL; + + LPDIRECT3DSURFACE9 s_efb_depth_surface = NULL; + LPDIRECT3DSURFACE9 s_efb_color_surface = NULL; + LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer = NULL; + + D3DFORMAT s_efb_color_surface_Format = D3DFMT_FORCE_DWORD; + D3DFORMAT s_efb_depth_surface_Format = D3DFMT_FORCE_DWORD; + D3DFORMAT s_efb_depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD; + m_realXFBSource.texture = NULL; + + // Simplest possible setup to start with. + int target_width = Renderer::GetFullTargetWidth(); + int target_height = Renderer::GetFullTargetHeight(); + + s_efb_color_surface_Format = D3DFMT_A8R8G8B8; + // Get the framebuffer texture + HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &s_efb_color_texture, NULL); + if(s_efb_color_texture) + { + hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface); + } + CHECK(hr, "Create color texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); + hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &s_efb_colorRead_texture, NULL); + CHECK(hr, "Create Color Read Texture (hr=%#x)", hr); + if(s_efb_colorRead_texture) + { + s_efb_colorRead_texture->GetSurfaceLevel(0, &s_efb_color_ReadBuffer); + } + // Create an offscreen surface that we can lock to retrieve the data + hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_color_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL); + CHECK(hr, "Create offscreen color surface (hr=%#x)", hr); + + // Select a Z-buffer format with hardware support + D3DFORMAT *DepthTexFormats = new D3DFORMAT[5]; + DepthTexFormats[0] = FOURCC_INTZ; + DepthTexFormats[1] = FOURCC_DF24; + DepthTexFormats[2] = FOURCC_RAWZ; + DepthTexFormats[3] = FOURCC_DF16; + DepthTexFormats[4] = D3DFMT_D24X8; + + for(int i = 0; i < 5; i++) + { + s_efb_depth_surface_Format = DepthTexFormats[i]; + // Create the framebuffer depth texture + hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format, + D3DPOOL_DEFAULT, &s_efb_depth_texture, NULL); + if (!FAILED(hr)) + break; + } + CHECK(hr, "Framebuffer depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); + // Get the Surface + if(s_efb_depth_texture) + { + s_efb_depth_texture->GetSurfaceLevel(0, &s_efb_depth_surface); + } + // Create a 4x4 pixel texture to work as a buffer for peeking + if(s_efb_depth_surface_Format == FOURCC_RAWZ || s_efb_depth_surface_Format == D3DFMT_D24X8) + { + DepthTexFormats[0] = D3DFMT_A8R8G8B8; + } + else + { + DepthTexFormats[0] = D3DFMT_R32F; + } + DepthTexFormats[1] = D3DFMT_A8R8G8B8; + + for(int i = 0; i < 2; i++) + { + s_efb_depth_ReadBuffer_Format = DepthTexFormats[i]; + // Get the framebuffer Depth texture + hr = D3D::dev->CreateTexture(4, 4, 1, D3DUSAGE_RENDERTARGET, s_efb_depth_ReadBuffer_Format, + D3DPOOL_DEFAULT, &s_efb_depthRead_texture, NULL); + if (!FAILED(hr)) + break; + } + + CHECK(hr, "Create depth read texture (hr=%#x)", hr); + if(s_efb_depthRead_texture) + { + s_efb_depthRead_texture->GetSurfaceLevel(0, &s_efb_depth_ReadBuffer); + } + // Create an offscreen surface that we can lock to retrieve the data + hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb_depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL); + CHECK(hr, "Create depth offscreen surface (hr=%#x)", hr); + delete [] DepthTexFormats; +} + +FramebufferManager::~FramebufferManager() +{ + SAFE_RELEASE(s_efb_depth_surface); + SAFE_RELEASE(s_efb_color_surface); + SAFE_RELEASE(s_efb_color_ReadBuffer); + SAFE_RELEASE(s_efb_depth_ReadBuffer); + SAFE_RELEASE(s_efb_color_OffScreenReadBuffer); + SAFE_RELEASE(s_efb_depth_OffScreenReadBuffer); + SAFE_RELEASE(s_efb_color_texture); + SAFE_RELEASE(s_efb_colorRead_texture); + SAFE_RELEASE(s_efb_depth_texture); + SAFE_RELEASE(s_efb_depthRead_texture); + + if (m_realXFBSource.texture) + m_realXFBSource.texture->Release(); + m_realXFBSource.texture = NULL; +} + +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + // TODO: + + //u8* xfb_in_ram = Memory_GetPtr(xfbAddr); + //if (!xfb_in_ram) + //{ + // WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + // return; + //} + + //TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); + //TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight); +} + +const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + return NULL; + + // TODO: + //xfbCount = 1; + + //m_realXFBSource.texWidth = fbWidth; + //m_realXFBSource.texHeight = fbHeight; + + //m_realXFBSource.srcAddr = xfbAddr; + //m_realXFBSource.srcWidth = fbWidth; + //m_realXFBSource.srcHeight = fbHeight; + + //if (!m_realXFBSource.texture) + //{ + // D3D::dev->CreateTexture(fbWidth, fbHeight, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + // D3DPOOL_DEFAULT, &m_realXFBSource.texture, NULL); + //} + + //// Decode YUYV data from GameCube RAM + //TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); + + //m_overlappingXFBArray[0] = &m_realXFBSource; + + //return &m_overlappingXFBArray[0]; +} + +XFBSourceBase *FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) +{ + XFBSource* const xfbs = new XFBSource; + D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &xfbs->texture, NULL); + + return xfbs; +} + +XFBSource::~XFBSource() +{ + texture->Release(); +} + +void XFBSource::CopyEFB(const TargetRectangle& efbSource) +{ + +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.h index d15ed0b17c..3f9b934399 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_FramebufferManager.h @@ -1,130 +1,130 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _FRAMEBUFFERMANAGER_D3D_H_ -#define _FRAMEBUFFERMANAGER_D3D_H_ - -#include -#include "DX9_D3DBase.h" - -#include "../FramebufferManager.h" - -// On the GameCube, the game sends a request for the graphics processor to -// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM -// called the XFB (External Framebuffer). The size and location of the XFB is -// decided at the time of the copy, and the format is always YUYV. The video -// interface is given a pointer to the XFB, which will be decoded and -// displayed on the TV. -// -// There are two ways for Dolphin to emulate this: -// -// Real XFB mode: -// -// Dolphin will behave like the GameCube and encode the EFB to -// a portion of GameCube RAM. The emulated video interface will decode the data -// for output to the screen. -// -// Advantages: Behaves exactly like the GameCube. -// Disadvantages: Resolution will be limited. -// -// Virtual XFB mode: -// -// When a request is made to copy the EFB to an XFB, Dolphin -// will remember the RAM location and size of the XFB in a Virtual XFB list. -// The video interface will look up the XFB in the list and use the enhanced -// data stored there, if available. -// -// Advantages: Enables high resolution graphics, better than real hardware. -// Disadvantages: If the GameCube CPU writes directly to the XFB (which is -// possible but uncommon), the Virtual XFB will not capture this information. - -// There may be multiple XFBs in GameCube RAM. This is the maximum number to -// virtualize. - -namespace DX9 -{ - -const int MAX_VIRTUAL_XFB = 8; - -inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) -{ - return !((aLower >= bUpper) || (bLower >= aUpper)); -} - -struct XFBSource : public XFBSourceBase -{ - XFBSource() : texture(NULL) {} - ~XFBSource(); - - void CopyEFB(const TargetRectangle& efbSource); - - LPDIRECT3DTEXTURE9 texture; -}; - -class FramebufferManager : public ::FramebufferManagerBase -{ -public: - FramebufferManager(); - ~FramebufferManager(); - - void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - - XFBSourceBase *CreateXFBSource(unsigned int target_width, unsigned int target_height); - - static LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc); - static LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle& sourceRc); - - static LPDIRECT3DSURFACE9 GetEFBColorRTSurface(); - static LPDIRECT3DSURFACE9 GetEFBDepthRTSurface(); - static LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface(); - static LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface(); - static D3DFORMAT GetEFBDepthRTSurfaceFormat(); - static D3DFORMAT GetEFBColorRTSurfaceFormat(); - static D3DFORMAT GetEFBDepthReadSurfaceFormat(); - static LPDIRECT3DSURFACE9 GetEFBColorReadSurface(); - static LPDIRECT3DSURFACE9 GetEFBDepthReadSurface(); - -private: - - void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); - - static XFBSource m_realXFBSource; // Only used in Real XFB mode - - const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; - - static LPDIRECT3DTEXTURE9 s_efb_color_texture;//Texture thats contains the color data of the render target - static LPDIRECT3DTEXTURE9 s_efb_colorRead_texture;//1 pixel texture for temporal data store - static LPDIRECT3DTEXTURE9 s_efb_depth_texture;//Texture thats contains the depth data of the render target - static LPDIRECT3DTEXTURE9 s_efb_depthRead_texture;//4 pixel texture for temporal data store - - static LPDIRECT3DSURFACE9 s_efb_depth_surface;//Depth Surface - static LPDIRECT3DSURFACE9 s_efb_color_surface;//Color Surface - static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;//Surface 0 of s_efb_colorRead_texture - static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;//Surface 0 of s_efb_depthRead_texture - static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data - static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data - - static D3DFORMAT s_efb_color_surface_Format;//Format of the color Surface - static D3DFORMAT s_efb_depth_surface_Format;//Format of the Depth Surface - static D3DFORMAT s_efb_depth_ReadBuffer_Format;//Format of the Depth color Read Surface -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _FRAMEBUFFERMANAGER_D3D_H_ +#define _FRAMEBUFFERMANAGER_D3D_H_ + +#include +#include "DX9_D3DBase.h" + +#include "../FramebufferManager.h" + +// On the GameCube, the game sends a request for the graphics processor to +// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM +// called the XFB (External Framebuffer). The size and location of the XFB is +// decided at the time of the copy, and the format is always YUYV. The video +// interface is given a pointer to the XFB, which will be decoded and +// displayed on the TV. +// +// There are two ways for Dolphin to emulate this: +// +// Real XFB mode: +// +// Dolphin will behave like the GameCube and encode the EFB to +// a portion of GameCube RAM. The emulated video interface will decode the data +// for output to the screen. +// +// Advantages: Behaves exactly like the GameCube. +// Disadvantages: Resolution will be limited. +// +// Virtual XFB mode: +// +// When a request is made to copy the EFB to an XFB, Dolphin +// will remember the RAM location and size of the XFB in a Virtual XFB list. +// The video interface will look up the XFB in the list and use the enhanced +// data stored there, if available. +// +// Advantages: Enables high resolution graphics, better than real hardware. +// Disadvantages: If the GameCube CPU writes directly to the XFB (which is +// possible but uncommon), the Virtual XFB will not capture this information. + +// There may be multiple XFBs in GameCube RAM. This is the maximum number to +// virtualize. + +namespace DX9 +{ + +const int MAX_VIRTUAL_XFB = 8; + +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return !((aLower >= bUpper) || (bLower >= aUpper)); +} + +struct XFBSource : public XFBSourceBase +{ + XFBSource() : texture(NULL) {} + ~XFBSource(); + + void CopyEFB(const TargetRectangle& efbSource); + + LPDIRECT3DTEXTURE9 texture; +}; + +class FramebufferManager : public ::FramebufferManagerBase +{ +public: + FramebufferManager(); + ~FramebufferManager(); + + void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + + XFBSourceBase *CreateXFBSource(unsigned int target_width, unsigned int target_height); + + static LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc); + static LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle& sourceRc); + + static LPDIRECT3DSURFACE9 GetEFBColorRTSurface(); + static LPDIRECT3DSURFACE9 GetEFBDepthRTSurface(); + static LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface(); + static LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface(); + static D3DFORMAT GetEFBDepthRTSurfaceFormat(); + static D3DFORMAT GetEFBColorRTSurfaceFormat(); + static D3DFORMAT GetEFBDepthReadSurfaceFormat(); + static LPDIRECT3DSURFACE9 GetEFBColorReadSurface(); + static LPDIRECT3DSURFACE9 GetEFBDepthReadSurface(); + +private: + + void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + + static XFBSource m_realXFBSource; // Only used in Real XFB mode + + const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; + + static LPDIRECT3DTEXTURE9 s_efb_color_texture;//Texture thats contains the color data of the render target + static LPDIRECT3DTEXTURE9 s_efb_colorRead_texture;//1 pixel texture for temporal data store + static LPDIRECT3DTEXTURE9 s_efb_depth_texture;//Texture thats contains the depth data of the render target + static LPDIRECT3DTEXTURE9 s_efb_depthRead_texture;//4 pixel texture for temporal data store + + static LPDIRECT3DSURFACE9 s_efb_depth_surface;//Depth Surface + static LPDIRECT3DSURFACE9 s_efb_color_surface;//Color Surface + static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;//Surface 0 of s_efb_colorRead_texture + static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;//Surface 0 of s_efb_depthRead_texture + static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data + static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data + + static D3DFORMAT s_efb_color_surface_Format;//Format of the color Surface + static D3DFORMAT s_efb_depth_surface_Format;//Format of the Depth Surface + static D3DFORMAT s_efb_depth_ReadBuffer_Format;//Format of the Depth color Read Surface +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_NativeVertexFormat.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_NativeVertexFormat.cpp index 5bad3639bf..aedcdd1580 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_NativeVertexFormat.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_NativeVertexFormat.cpp @@ -1,178 +1,178 @@ - -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "DX9_D3DBase.h" - -#include "Profiler.h" -#include "x64Emitter.h" -#include "ABI.h" -#include "MemoryUtil.h" -#include "VertexShaderGen.h" - -#include "CPMemory.h" - -#include "DX9_VertexManager.h" - -namespace DX9 -{ - -class D3DVertexFormat : public NativeVertexFormat -{ - LPDIRECT3DVERTEXDECLARATION9 d3d_decl; - -public: - D3DVertexFormat(); - ~D3DVertexFormat(); - virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); - virtual void SetupVertexPointers() const; -}; - -NativeVertexFormat *VertexManager::CreateNativeVertexFormat() -{ - return new D3DVertexFormat(); -} - -D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL) -{ -} - -D3DVertexFormat::~D3DVertexFormat() -{ - if (d3d_decl) - { - d3d_decl->Release(); - d3d_decl = NULL; - } -} - -D3DDECLTYPE VarToD3D(VarType t, int size) -{ - if (t < 0 || t > 4) { - PanicAlert("VarToD3D: Invalid VarType %i", t); - } - static const D3DDECLTYPE lookup1[5] = { - D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT1, - }; - static const D3DDECLTYPE lookup2[5] = { - D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_SHORT2N, D3DDECLTYPE_USHORT2N, D3DDECLTYPE_FLOAT2, - }; - static const D3DDECLTYPE lookup3[5] = { - D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT3, - }; - // Sadly, D3D9 has no SBYTE4N. D3D10 does, though. - static const D3DDECLTYPE lookup4[5] = { - D3DDECLTYPE_UNUSED, D3DDECLTYPE_UBYTE4N, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT4, - }; - D3DDECLTYPE retval = D3DDECLTYPE_UNUSED; - switch (size) { - case 1: retval = lookup1[t]; break; - case 2: retval = lookup2[t]; break; - case 3: retval = lookup3[t]; break; - case 4: retval = lookup4[t]; break; - default: PanicAlert("VarToD3D: size wrong (%i)", size); break; - } - if (retval == D3DDECLTYPE_UNUSED) { - PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size); - } - return retval; -} - -void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) -{ - vertex_stride = _vtx_decl.stride; - - D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32]; - memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32); - - // There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream. - // Same for method. - - // So, here we go. First position: - int elem_idx = 0; - elems[elem_idx].Offset = 0; // Positions are always first, at position 0. Always float3. - elems[elem_idx].Type = D3DDECLTYPE_FLOAT3; - elems[elem_idx].Usage = D3DDECLUSAGE_POSITION; - ++elem_idx; - - for (int i = 0; i < 3; i++) - { - if (_vtx_decl.normal_offset[i] > 0) - { - elems[elem_idx].Offset = _vtx_decl.normal_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size); - elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - for (int i = 0; i < 2; i++) - { - if (_vtx_decl.color_offset[i] > 0) - { - elems[elem_idx].Offset = _vtx_decl.color_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type, 4); - elems[elem_idx].Usage = D3DDECLUSAGE_COLOR; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - for (int i = 0; i < 8; i++) - { - if (_vtx_decl.texcoord_offset[i] > 0) - { - elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i]; - elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]); - elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD; - elems[elem_idx].UsageIndex = i; - ++elem_idx; - } - } - - if (_vtx_decl.posmtx_offset != -1) - { - elems[elem_idx].Offset = _vtx_decl.posmtx_offset; - elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES; - elems[elem_idx].Type = D3DDECLTYPE_D3DCOLOR; - elems[elem_idx].UsageIndex = 0; - ++elem_idx; - } - - // End marker - elems[elem_idx].Stream = 0xff; - elems[elem_idx].Type = D3DDECLTYPE_UNUSED; - ++elem_idx; - - if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl))) - { - PanicAlert("Failed to create D3D vertex declaration!"); - return; - } - delete [] elems; -} - -void D3DVertexFormat::SetupVertexPointers() const -{ - if (d3d_decl) - D3D::SetVertexDeclaration(d3d_decl); - else - ERROR_LOG(VIDEO, "invalid d3d decl"); -} - -} + +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "DX9_D3DBase.h" + +#include "Profiler.h" +#include "x64Emitter.h" +#include "ABI.h" +#include "MemoryUtil.h" +#include "VertexShaderGen.h" + +#include "CPMemory.h" + +#include "DX9_VertexManager.h" + +namespace DX9 +{ + +class D3DVertexFormat : public NativeVertexFormat +{ + LPDIRECT3DVERTEXDECLARATION9 d3d_decl; + +public: + D3DVertexFormat(); + ~D3DVertexFormat(); + virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); + virtual void SetupVertexPointers() const; +}; + +NativeVertexFormat *VertexManager::CreateNativeVertexFormat() +{ + return new D3DVertexFormat(); +} + +D3DVertexFormat::D3DVertexFormat() : d3d_decl(NULL) +{ +} + +D3DVertexFormat::~D3DVertexFormat() +{ + if (d3d_decl) + { + d3d_decl->Release(); + d3d_decl = NULL; + } +} + +D3DDECLTYPE VarToD3D(VarType t, int size) +{ + if (t < 0 || t > 4) { + PanicAlert("VarToD3D: Invalid VarType %i", t); + } + static const D3DDECLTYPE lookup1[5] = { + D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT1, + }; + static const D3DDECLTYPE lookup2[5] = { + D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_SHORT2N, D3DDECLTYPE_USHORT2N, D3DDECLTYPE_FLOAT2, + }; + static const D3DDECLTYPE lookup3[5] = { + D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_UNUSED, D3DDECLTYPE_FLOAT3, + }; + // Sadly, D3D9 has no SBYTE4N. D3D10 does, though. + static const D3DDECLTYPE lookup4[5] = { + D3DDECLTYPE_UNUSED, D3DDECLTYPE_UBYTE4N, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_USHORT4N, D3DDECLTYPE_FLOAT4, + }; + D3DDECLTYPE retval = D3DDECLTYPE_UNUSED; + switch (size) { + case 1: retval = lookup1[t]; break; + case 2: retval = lookup2[t]; break; + case 3: retval = lookup3[t]; break; + case 4: retval = lookup4[t]; break; + default: PanicAlert("VarToD3D: size wrong (%i)", size); break; + } + if (retval == D3DDECLTYPE_UNUSED) { + PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size); + } + return retval; +} + +void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) +{ + vertex_stride = _vtx_decl.stride; + + D3DVERTEXELEMENT9 *elems = new D3DVERTEXELEMENT9[32]; + memset(elems, 0, sizeof(D3DVERTEXELEMENT9) * 32); + + // There's only one stream and it's 0, so the above memset takes care of that - no need to set Stream. + // Same for method. + + // So, here we go. First position: + int elem_idx = 0; + elems[elem_idx].Offset = 0; // Positions are always first, at position 0. Always float3. + elems[elem_idx].Type = D3DDECLTYPE_FLOAT3; + elems[elem_idx].Usage = D3DDECLUSAGE_POSITION; + ++elem_idx; + + for (int i = 0; i < 3; i++) + { + if (_vtx_decl.normal_offset[i] > 0) + { + elems[elem_idx].Offset = _vtx_decl.normal_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size); + elems[elem_idx].Usage = D3DDECLUSAGE_NORMAL; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + for (int i = 0; i < 2; i++) + { + if (_vtx_decl.color_offset[i] > 0) + { + elems[elem_idx].Offset = _vtx_decl.color_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.color_gl_type, 4); + elems[elem_idx].Usage = D3DDECLUSAGE_COLOR; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + for (int i = 0; i < 8; i++) + { + if (_vtx_decl.texcoord_offset[i] > 0) + { + elems[elem_idx].Offset = _vtx_decl.texcoord_offset[i]; + elems[elem_idx].Type = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]); + elems[elem_idx].Usage = D3DDECLUSAGE_TEXCOORD; + elems[elem_idx].UsageIndex = i; + ++elem_idx; + } + } + + if (_vtx_decl.posmtx_offset != -1) + { + elems[elem_idx].Offset = _vtx_decl.posmtx_offset; + elems[elem_idx].Usage = D3DDECLUSAGE_BLENDINDICES; + elems[elem_idx].Type = D3DDECLTYPE_D3DCOLOR; + elems[elem_idx].UsageIndex = 0; + ++elem_idx; + } + + // End marker + elems[elem_idx].Stream = 0xff; + elems[elem_idx].Type = D3DDECLTYPE_UNUSED; + ++elem_idx; + + if (FAILED(D3D::dev->CreateVertexDeclaration(elems, &d3d_decl))) + { + PanicAlert("Failed to create D3D vertex declaration!"); + return; + } + delete [] elems; +} + +void D3DVertexFormat::SetupVertexPointers() const +{ + if (d3d_decl) + D3D::SetVertexDeclaration(d3d_decl); + else + ERROR_LOG(VIDEO, "invalid d3d decl"); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.cpp index 90544d0114..7a7ff6aceb 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.cpp @@ -1,392 +1,392 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -#include "Common.h" -#include "Hash.h" -#include "FileUtil.h" -#include "LinearDiskCache.h" - -#include "DX9_D3DBase.h" -#include "DX9_D3DShader.h" -#include "Statistics.h" -#include "VideoConfig.h" -#include "PixelShaderGen.h" -#include "PixelShaderManager.h" -#include "DX9_PixelShaderCache.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" -#include "ImageWrite.h" - -#include "../Main.h" - -//#include "Debugger/Debugger.h" - -namespace DX9 -{ - -PixelShaderCache::PSCache PixelShaderCache::PixelShaders; -const PixelShaderCache::PSCacheEntry *PixelShaderCache::last_entry; - -static LinearDiskCache g_ps_disk_cache; -static std::set unique_shaders; - -#define MAX_SSAA_SHADERS 3 - -static LPDIRECT3DPIXELSHADER9 s_ColorMatrixProgram[MAX_SSAA_SHADERS]; -static LPDIRECT3DPIXELSHADER9 s_ColorCopyProgram[MAX_SSAA_SHADERS]; -static LPDIRECT3DPIXELSHADER9 s_DepthMatrixProgram[MAX_SSAA_SHADERS]; -static LPDIRECT3DPIXELSHADER9 s_ClearProgram = 0; - -LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram(int SSAAMode) -{ - return s_ColorMatrixProgram[SSAAMode % MAX_SSAA_SHADERS]; -} - -LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetDepthMatrixProgram(int SSAAMode) -{ - return s_DepthMatrixProgram[SSAAMode % MAX_SSAA_SHADERS]; -} - -LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorCopyProgram(int SSAAMode) -{ - return s_ColorCopyProgram[SSAAMode % MAX_SSAA_SHADERS]; -} - -LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetClearProgram() -{ - return s_ClearProgram; -} - -void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - float f[4] = { f1, f2, f3, f4 }; - D3D::dev->SetPixelShaderConstantF(const_number, f, 1); -} - -void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f) -{ - D3D::dev->SetPixelShaderConstantF(const_number, f, 1); -} - -void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) -{ - D3D::dev->SetPixelShaderConstantF(const_number, f, count); -} - -class PixelShaderCacheInserter : public LinearDiskCacheReader { -public: - void Read(const u8 *key, int key_size, const u8 *value, int value_size) - { - PIXELSHADERUID uid; - if (key_size != sizeof(uid)) { - ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache"); - return; - } - memcpy(&uid, key, key_size); - PixelShaderCache::InsertByteCode(uid, value, value_size, false); - } -}; - -PixelShaderCache::PixelShaderCache() -{ - //program used for clear screen - char pprog[3072]; - sprintf(pprog, "void main(\n" - "out float4 ocol0 : COLOR0,\n" - " in float4 incol0 : COLOR0){\n" - "ocol0 = incol0;\n" - "}\n"); - s_ClearProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //Used for Copy/resolve the color buffer - //1 Sample - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float2 uv0 : TEXCOORD0){\n" - "ocol0 = tex2D(samp0,uv0);\n" - "}\n"); - s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //1 Samples SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1){\n" - "ocol0 = tex2D(samp0,uv0.xy);\n" - "}\n"); - s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //4 Samples SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1,\n" - "in float4 uv2 : TEXCOORD2,\n" - "in float4 uv3 : TEXCOORD3){\n" - "ocol0 = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25;\n" - "}\n"); - s_ColorCopyProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - - - //Color conversion Programs - //1 sample - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0){\n" - "float4 texcol = tex2D(samp0,uv0);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //1 samples SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1){\n" - "float4 texcol = tex2D(samp0,uv0.xy);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //4 samples SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1,\n" - "in float4 uv2 : TEXCOORD2,\n" - "in float4 uv3 : TEXCOORD3){\n" - "float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_ColorMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //Depth copy programs - //1 sample - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0){\n" - "float4 texcol = tex2D(samp0,uv0);\n" - "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" - "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //1 sample SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1){\n" - "float4 texcol = tex2D(samp0,uv0.xy);\n" - "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" - "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - //4 sample SSAA - sprintf(pprog, "uniform sampler samp0 : register(s0);\n" - "uniform float4 cColMatrix[5] : register(c%d);\n" - "void main(\n" - "out float4 ocol0 : COLOR0,\n" - "in float4 uv0 : TEXCOORD0,\n" - "in float4 uv1 : TEXCOORD1,\n" - "in float4 uv2 : TEXCOORD2,\n" - "in float4 uv3 : TEXCOORD3){\n" - "float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n" - "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" - "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" - "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" - "}\n",C_COLORMATRIX); - s_DepthMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); - - Clear(); - - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - SETSTAT(stats.numPixelShadersCreated, 0); - SETSTAT(stats.numPixelShadersAlive, 0); - - char cache_filename[MAX_PATH]; - sprintf(cache_filename, "%sdx9-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); - PixelShaderCacheInserter inserter; - int read_items = g_ps_disk_cache.OpenAndRead(cache_filename, &inserter); -} - -// ONLY to be used during shutdown. -void PixelShaderCache::Clear() -{ - PSCache::iterator iter = PixelShaders.begin(); - for (; iter != PixelShaders.end(); ++iter) - iter->second.Destroy(); - PixelShaders.clear(); - - memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); -} - -PixelShaderCache::~PixelShaderCache() -{ - for(int i = 0;i < MAX_SSAA_SHADERS; i++) - { - if (s_ColorMatrixProgram[i]) s_ColorMatrixProgram[i]->Release(); - s_ColorMatrixProgram[i] = NULL; - if (s_ColorCopyProgram[i]) s_ColorCopyProgram[i]->Release(); - s_ColorCopyProgram[i] = NULL; - if (s_DepthMatrixProgram[i]) s_DepthMatrixProgram[i]->Release(); - s_DepthMatrixProgram[i] = NULL; - } - if (s_ClearProgram) s_ClearProgram->Release(); - s_ClearProgram = NULL; - - Clear(); - g_ps_disk_cache.Sync(); - g_ps_disk_cache.Close(); - - unique_shaders.clear(); -} - -bool PixelShaderCache::SetShader(bool dstAlpha) -{ - PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlpha); - - // Is the shader already set? - if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) - { - PSCache::const_iterator iter = PixelShaders.find(uid); - if (iter != PixelShaders.end() && iter->second.shader) - return true; // Sure, we're done. - else - return false; // ?? something is wrong. - } - - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); - - // Is the shader already in the cache? - PSCache::iterator iter; - iter = PixelShaders.find(uid); - if (iter != PixelShaders.end()) - { - iter->second.frameCount = frameCount; - const PSCacheEntry &entry = iter->second; - last_entry = &entry; - - if (entry.shader) - { - D3D::SetPixelShader(entry.shader); - return true; - } - else - return false; - } - - // OK, need to generate and compile it. - const char *code = GeneratePixelShaderCode(dstAlpha, API_D3D9); - - u32 code_hash = HashAdler32((const u8 *)code, strlen(code)); - unique_shaders.insert(code_hash); - SETSTAT(stats.numUniquePixelShaders, unique_shaders.size()); - - #if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - - SaveData(szTemp, code); - } - #endif - - u8 *bytecode = 0; - int bytecodelen = 0; - if (!D3D::CompilePixelShader(code, (int)strlen(code), &bytecode, &bytecodelen)) { - if (g_ActiveConfig.bShowShaderErrors) - { - PanicAlert("Failed to compile Pixel Shader:\n\n%s", code); - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - SaveData(szTemp, code); - } - return false; - } - - // Here we have the UID and the byte code. Insert it into the disk cache. - g_ps_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen); - g_ps_disk_cache.Sync(); - - // And insert it into the shader cache. - bool result = InsertByteCode(uid, bytecode, bytecodelen, true); - delete [] bytecode; - return result; -} - -bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) { - LPDIRECT3DPIXELSHADER9 shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); - - // Make an entry in the table - PSCacheEntry newentry; - newentry.shader = shader; - newentry.frameCount = frameCount; - PixelShaders[uid] = newentry; - last_entry = &PixelShaders[uid]; - - if (!shader) { - // INCSTAT(stats.numPixelShadersFailed); - return false; - } - - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, (int)PixelShaders.size()); - if (activate) - { - D3D::SetPixelShader(shader); - } - return true; -} - - -#if defined(_DEBUG) || defined(DEBUGFAST) -std::string PixelShaderCache::GetCurrentShaderCode() -{ - if (last_entry) - return last_entry->code; - else - return "(no shader)\n"; -} -#endif - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include + +#include "Common.h" +#include "Hash.h" +#include "FileUtil.h" +#include "LinearDiskCache.h" + +#include "DX9_D3DBase.h" +#include "DX9_D3DShader.h" +#include "Statistics.h" +#include "VideoConfig.h" +#include "PixelShaderGen.h" +#include "PixelShaderManager.h" +#include "DX9_PixelShaderCache.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" +#include "ImageWrite.h" + +#include "../Main.h" + +//#include "Debugger/Debugger.h" + +namespace DX9 +{ + +PixelShaderCache::PSCache PixelShaderCache::PixelShaders; +const PixelShaderCache::PSCacheEntry *PixelShaderCache::last_entry; + +static LinearDiskCache g_ps_disk_cache; +static std::set unique_shaders; + +#define MAX_SSAA_SHADERS 3 + +static LPDIRECT3DPIXELSHADER9 s_ColorMatrixProgram[MAX_SSAA_SHADERS]; +static LPDIRECT3DPIXELSHADER9 s_ColorCopyProgram[MAX_SSAA_SHADERS]; +static LPDIRECT3DPIXELSHADER9 s_DepthMatrixProgram[MAX_SSAA_SHADERS]; +static LPDIRECT3DPIXELSHADER9 s_ClearProgram = 0; + +LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram(int SSAAMode) +{ + return s_ColorMatrixProgram[SSAAMode % MAX_SSAA_SHADERS]; +} + +LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetDepthMatrixProgram(int SSAAMode) +{ + return s_DepthMatrixProgram[SSAAMode % MAX_SSAA_SHADERS]; +} + +LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorCopyProgram(int SSAAMode) +{ + return s_ColorCopyProgram[SSAAMode % MAX_SSAA_SHADERS]; +} + +LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetClearProgram() +{ + return s_ClearProgram; +} + +void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + float f[4] = { f1, f2, f3, f4 }; + D3D::dev->SetPixelShaderConstantF(const_number, f, 1); +} + +void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f) +{ + D3D::dev->SetPixelShaderConstantF(const_number, f, 1); +} + +void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) +{ + D3D::dev->SetPixelShaderConstantF(const_number, f, count); +} + +class PixelShaderCacheInserter : public LinearDiskCacheReader { +public: + void Read(const u8 *key, int key_size, const u8 *value, int value_size) + { + PIXELSHADERUID uid; + if (key_size != sizeof(uid)) { + ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache"); + return; + } + memcpy(&uid, key, key_size); + PixelShaderCache::InsertByteCode(uid, value, value_size, false); + } +}; + +PixelShaderCache::PixelShaderCache() +{ + //program used for clear screen + char pprog[3072]; + sprintf(pprog, "void main(\n" + "out float4 ocol0 : COLOR0,\n" + " in float4 incol0 : COLOR0){\n" + "ocol0 = incol0;\n" + "}\n"); + s_ClearProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //Used for Copy/resolve the color buffer + //1 Sample + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float2 uv0 : TEXCOORD0){\n" + "ocol0 = tex2D(samp0,uv0);\n" + "}\n"); + s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //1 Samples SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1){\n" + "ocol0 = tex2D(samp0,uv0.xy);\n" + "}\n"); + s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //4 Samples SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1,\n" + "in float4 uv2 : TEXCOORD2,\n" + "in float4 uv3 : TEXCOORD3){\n" + "ocol0 = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25;\n" + "}\n"); + s_ColorCopyProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + + + //Color conversion Programs + //1 sample + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0){\n" + "float4 texcol = tex2D(samp0,uv0);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //1 samples SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1){\n" + "float4 texcol = tex2D(samp0,uv0.xy);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //4 samples SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1,\n" + "in float4 uv2 : TEXCOORD2,\n" + "in float4 uv3 : TEXCOORD3){\n" + "float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_ColorMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //Depth copy programs + //1 sample + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0){\n" + "float4 texcol = tex2D(samp0,uv0);\n" + "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" + "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //1 sample SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1){\n" + "float4 texcol = tex2D(samp0,uv0.xy);\n" + "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" + "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + //4 sample SSAA + sprintf(pprog, "uniform sampler samp0 : register(s0);\n" + "uniform float4 cColMatrix[5] : register(c%d);\n" + "void main(\n" + "out float4 ocol0 : COLOR0,\n" + "in float4 uv0 : TEXCOORD0,\n" + "in float4 uv1 : TEXCOORD1,\n" + "in float4 uv2 : TEXCOORD2,\n" + "in float4 uv3 : TEXCOORD3){\n" + "float4 texcol = (tex2D(samp0,uv1.xy) + tex2D(samp0,uv1.wz) + tex2D(samp0,uv2.xy) + tex2D(samp0,uv2.wz))*0.25f;\n" + "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n" + "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n" + "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" + "}\n",C_COLORMATRIX); + s_DepthMatrixProgram[2] = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog)); + + Clear(); + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + SETSTAT(stats.numPixelShadersCreated, 0); + SETSTAT(stats.numPixelShadersAlive, 0); + + char cache_filename[MAX_PATH]; + sprintf(cache_filename, "%sdx9-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); + PixelShaderCacheInserter inserter; + int read_items = g_ps_disk_cache.OpenAndRead(cache_filename, &inserter); +} + +// ONLY to be used during shutdown. +void PixelShaderCache::Clear() +{ + PSCache::iterator iter = PixelShaders.begin(); + for (; iter != PixelShaders.end(); ++iter) + iter->second.Destroy(); + PixelShaders.clear(); + + memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); +} + +PixelShaderCache::~PixelShaderCache() +{ + for(int i = 0;i < MAX_SSAA_SHADERS; i++) + { + if (s_ColorMatrixProgram[i]) s_ColorMatrixProgram[i]->Release(); + s_ColorMatrixProgram[i] = NULL; + if (s_ColorCopyProgram[i]) s_ColorCopyProgram[i]->Release(); + s_ColorCopyProgram[i] = NULL; + if (s_DepthMatrixProgram[i]) s_DepthMatrixProgram[i]->Release(); + s_DepthMatrixProgram[i] = NULL; + } + if (s_ClearProgram) s_ClearProgram->Release(); + s_ClearProgram = NULL; + + Clear(); + g_ps_disk_cache.Sync(); + g_ps_disk_cache.Close(); + + unique_shaders.clear(); +} + +bool PixelShaderCache::SetShader(bool dstAlpha) +{ + PIXELSHADERUID uid; + GetPixelShaderId(&uid, dstAlpha); + + // Is the shader already set? + if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount) + { + PSCache::const_iterator iter = PixelShaders.find(uid); + if (iter != PixelShaders.end() && iter->second.shader) + return true; // Sure, we're done. + else + return false; // ?? something is wrong. + } + + memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + + // Is the shader already in the cache? + PSCache::iterator iter; + iter = PixelShaders.find(uid); + if (iter != PixelShaders.end()) + { + iter->second.frameCount = frameCount; + const PSCacheEntry &entry = iter->second; + last_entry = &entry; + + if (entry.shader) + { + D3D::SetPixelShader(entry.shader); + return true; + } + else + return false; + } + + // OK, need to generate and compile it. + const char *code = GeneratePixelShaderCode(dstAlpha, API_D3D9); + + u32 code_hash = HashAdler32((const u8 *)code, strlen(code)); + unique_shaders.insert(code_hash); + SETSTAT(stats.numUniquePixelShaders, unique_shaders.size()); + + #if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + + SaveData(szTemp, code); + } + #endif + + u8 *bytecode = 0; + int bytecodelen = 0; + if (!D3D::CompilePixelShader(code, (int)strlen(code), &bytecode, &bytecodelen)) { + if (g_ActiveConfig.bShowShaderErrors) + { + PanicAlert("Failed to compile Pixel Shader:\n\n%s", code); + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + SaveData(szTemp, code); + } + return false; + } + + // Here we have the UID and the byte code. Insert it into the disk cache. + g_ps_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen); + g_ps_disk_cache.Sync(); + + // And insert it into the shader cache. + bool result = InsertByteCode(uid, bytecode, bytecodelen, true); + delete [] bytecode; + return result; +} + +bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) { + LPDIRECT3DPIXELSHADER9 shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen); + + // Make an entry in the table + PSCacheEntry newentry; + newentry.shader = shader; + newentry.frameCount = frameCount; + PixelShaders[uid] = newentry; + last_entry = &PixelShaders[uid]; + + if (!shader) { + // INCSTAT(stats.numPixelShadersFailed); + return false; + } + + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, (int)PixelShaders.size()); + if (activate) + { + D3D::SetPixelShader(shader); + } + return true; +} + + +#if defined(_DEBUG) || defined(DEBUGFAST) +std::string PixelShaderCache::GetCurrentShaderCode() +{ + if (last_entry) + return last_entry->code; + else + return "(no shader)\n"; +} +#endif + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.h index 7506b3466b..9978477ca8 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_PixelShaderCache.h @@ -1,89 +1,89 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _PIXELSHADERCACHE_H -#define _PIXELSHADERCACHE_H - -#include "Common.h" -#include "LinearDiskCache.h" -#include "DX9_D3DBase.h" - -#include - -#include "PixelShaderGen.h" -#include "VertexShaderGen.h" - -#include "../PixelShaderCache.h" - -namespace DX9 -{ - -typedef u32 tevhash; - -tevhash GetCurrentTEV(); - -class PixelShaderCache : public ::PixelShaderCacheBase -{ -private: - struct PSCacheEntry - { - LPDIRECT3DPIXELSHADER9 shader; - bool owns_shader; - int frameCount; -#if defined(_DEBUG) || defined(DEBUGFAST) - std::string code; -#endif - PSCacheEntry() : shader(NULL), owns_shader(true), frameCount(0) {} - void Destroy() - { - if (shader && owns_shader) - shader->Release(); - shader = NULL; - } - }; - - typedef std::map PSCache; - - static PSCache PixelShaders; - static const PSCacheEntry *last_entry; - static void Clear(); - -public: - PixelShaderCache(); - ~PixelShaderCache(); - - void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetPSConstant4fv(unsigned int const_number, const float* f); - void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f); - - bool SetShader(bool dstAlpha); - - static bool InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate); - static LPDIRECT3DPIXELSHADER9 GetColorMatrixProgram(int SSAAMode); - static LPDIRECT3DPIXELSHADER9 GetColorCopyProgram(int SSAAMode); - static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram(int SSAAMode); - static LPDIRECT3DPIXELSHADER9 GetClearProgram(); - -#if defined(_DEBUG) || defined(DEBUGFAST) - static std::string GetCurrentShaderCode(); -#endif - static LPDIRECT3DPIXELSHADER9 CompileCgShader(const char *pstrprogram); -}; - -} - -#endif // _PIXELSHADERCACHE_H +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _PIXELSHADERCACHE_H +#define _PIXELSHADERCACHE_H + +#include "Common.h" +#include "LinearDiskCache.h" +#include "DX9_D3DBase.h" + +#include + +#include "PixelShaderGen.h" +#include "VertexShaderGen.h" + +#include "../PixelShaderCache.h" + +namespace DX9 +{ + +typedef u32 tevhash; + +tevhash GetCurrentTEV(); + +class PixelShaderCache : public ::PixelShaderCacheBase +{ +private: + struct PSCacheEntry + { + LPDIRECT3DPIXELSHADER9 shader; + bool owns_shader; + int frameCount; +#if defined(_DEBUG) || defined(DEBUGFAST) + std::string code; +#endif + PSCacheEntry() : shader(NULL), owns_shader(true), frameCount(0) {} + void Destroy() + { + if (shader && owns_shader) + shader->Release(); + shader = NULL; + } + }; + + typedef std::map PSCache; + + static PSCache PixelShaders; + static const PSCacheEntry *last_entry; + static void Clear(); + +public: + PixelShaderCache(); + ~PixelShaderCache(); + + void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetPSConstant4fv(unsigned int const_number, const float* f); + void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f); + + bool SetShader(bool dstAlpha); + + static bool InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate); + static LPDIRECT3DPIXELSHADER9 GetColorMatrixProgram(int SSAAMode); + static LPDIRECT3DPIXELSHADER9 GetColorCopyProgram(int SSAAMode); + static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram(int SSAAMode); + static LPDIRECT3DPIXELSHADER9 GetClearProgram(); + +#if defined(_DEBUG) || defined(DEBUGFAST) + static std::string GetCurrentShaderCode(); +#endif + static LPDIRECT3DPIXELSHADER9 CompileCgShader(const char *pstrprogram); +}; + +} + +#endif // _PIXELSHADERCACHE_H diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.cpp index 7094d35c00..12845170af 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.cpp @@ -1,960 +1,960 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include -#include - -#include "StringUtil.h" -#include "Common.h" -#include "Atomic.h" -#include "FileUtil.h" -#include "Thread.h" -#include "Timer.h" -#include "Statistics.h" - -#include "VideoConfig.h" -#include "main.h" -#include "DX9_VertexManager.h" -#include "DX9_Render.h" -#include "OpcodeDecoding.h" -#include "BPStructs.h" -#include "XFStructs.h" -#include "DX9_D3DUtil.h" -#include "VertexShaderManager.h" -#include "PixelShaderManager.h" -#include "DX9_VertexShaderCache.h" -#include "DX9_PixelShaderCache.h" -#include "VertexLoaderManager.h" -#include "DX9_TextureCache.h" -#include "EmuWindow.h" -#include "AVIDump.h" -#include "OnScreenDisplay.h" -#include "DX9_FramebufferManager.h" -#include "Fifo.h" -#include "DX9_TextureConverter.h" -#include "DLCache.h" - -//#include "debugger/debugger.h" - -#include "DX9_Render.h" - -namespace DX9 -{ - -bool Renderer::IS_AMD; - -// State translation lookup tables -static const D3DBLEND d3dSrcFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_DESTCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - -static const D3DBLEND d3dDestFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_SRCCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - -static const D3DBLENDOP d3dLogicOpop[16] = -{ - D3DBLENDOP_ADD, - D3DBLENDOP_ADD, - D3DBLENDOP_SUBTRACT, - D3DBLENDOP_ADD, - D3DBLENDOP_REVSUBTRACT, - D3DBLENDOP_ADD, - D3DBLENDOP_MAX, - D3DBLENDOP_ADD, - - D3DBLENDOP_MAX, - D3DBLENDOP_MAX, - D3DBLENDOP_ADD, - D3DBLENDOP_ADD, - D3DBLENDOP_ADD, - D3DBLENDOP_ADD, - D3DBLENDOP_ADD, - D3DBLENDOP_ADD -}; - -static const D3DBLEND d3dLogicOpSrcFactors[16] = -{ - D3DBLEND_ZERO, - D3DBLEND_DESTCOLOR, - D3DBLEND_ONE, - D3DBLEND_ONE, - D3DBLEND_DESTCOLOR, - D3DBLEND_ZERO, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_INVDESTCOLOR, - - D3DBLEND_INVSRCCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_ONE, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_ONE -}; - -static const D3DBLEND d3dLogicOpDestFactors[16] = -{ - D3DBLEND_ZERO, - D3DBLEND_ZERO, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_ONE, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_ONE, - - D3DBLEND_INVDESTCOLOR, - D3DBLEND_SRCCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_ONE, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_ONE -}; - -static const D3DCULL d3dCullModes[4] = -{ - D3DCULL_NONE, - D3DCULL_CCW, - D3DCULL_CW, - D3DCULL_CCW -}; - -static const D3DCMPFUNC d3dCmpFuncs[8] = -{ - D3DCMP_NEVER, - D3DCMP_LESS, - D3DCMP_EQUAL, - D3DCMP_LESSEQUAL, - D3DCMP_GREATER, - D3DCMP_NOTEQUAL, - D3DCMP_GREATEREQUAL, - D3DCMP_ALWAYS -}; - -static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] = -{ - D3DTEXF_NONE, - D3DTEXF_POINT, - D3DTEXF_LINEAR, - D3DTEXF_NONE, //reserved -}; - -static const D3DTEXTUREADDRESS d3dClamps[4] = -{ - D3DTADDRESS_CLAMP, - D3DTADDRESS_WRAP, - D3DTADDRESS_MIRROR, - D3DTADDRESS_WRAP //reserved -}; - -void Renderer::SetupDeviceObjects() -{ - D3D::font.Init(); - g_framebuffer_manager = new FramebufferManager; - - VertexShaderManager::Dirty(); - PixelShaderManager::Dirty(); - // TODO: - //TextureConverter::Init(); - - // To avoid shader compilation stutters, read back all shaders from cache. - // Texture cache will recreate themselves over time. -} - -// Kill off all POOL_DEFAULT device objects. -void Renderer::TeardownDeviceObjects() -{ - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - - delete g_framebuffer_manager; - - //D3D::font.Shutdown(); - // TODO: - //TextureConverter::Shutdown(); -} - -Renderer::Renderer() -{ - UpdateActiveConfig(); - int fullScreenRes, x, y, w_temp, h_temp; - s_blendMode = 0; - // Multisample Anti-aliasing hasn't been implemented yet use supersamling instead - int backbuffer_ms_mode = 0; - - g_VideoInitialize.pRequestWindowSize(x, y, w_temp, h_temp); - - for (fullScreenRes = 0; fullScreenRes < (int)D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size(); fullScreenRes++) - { - if ((D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].xres == w_temp) && - (D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].yres == h_temp)) - break; - } - if (fullScreenRes == D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size()) - fullScreenRes = 0; - - D3D::Init(); - - D3D::Create(g_ActiveConfig.iAdapter, EmuWindow::GetWnd(), - fullScreenRes, backbuffer_ms_mode, false); - - IS_AMD = D3D::IsATIDevice(); - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - - s_XFB_width = MAX_XFB_WIDTH; - s_XFB_height = MAX_XFB_HEIGHT; - - FramebufferSize(s_backbuffer_width, s_backbuffer_height); - - // We're not using fixed function. - // Let's just set the matrices to identity to be sure. - D3DXMATRIX mtx; - D3DXMatrixIdentity(&mtx); - D3D::dev->SetTransform(D3DTS_VIEW, &mtx); - D3D::dev->SetTransform(D3DTS_WORLD, &mtx); - - SetupDeviceObjects(); - - for (int stage = 0; stage < 8; stage++) - D3D::SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, g_ActiveConfig.iMaxAnisotropy); - - D3DVIEWPORT9 vp; - vp.X = 0; - vp.Y = 0; - vp.Width = s_backbuffer_width; - vp.Height = s_backbuffer_height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, 0x0, 0, 0); - - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - vp.X = (s_Fulltarget_width - s_target_width) / 2; - vp.Y = (s_Fulltarget_height - s_target_height) / 2; - vp.Width = s_target_width; - vp.Height = s_target_height; - D3D::dev->SetViewport(&vp); - D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0); - D3D::BeginFrame(); - D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true); - //return true; -} - -Renderer::~Renderer() -{ - TeardownDeviceObjects(); - D3D::EndFrame(); - D3D::Present(); - D3D::Close(); -} - -void formatBufferDump(const char *in, char *out, int w, int h, int p) -{ - for (int y = 0; y < h; y++) - { - const char *line = in + (h - y - 1) * p; - for (int x = 0; x < w; x++) - { - memcpy(out, line, 3); - out += 3; - line += 4; - } - } -} - -// With D3D, we have to resize the backbuffer if the window changed -// size. -bool Renderer::CheckForResize() -{ - while (EmuWindow::IsSizing()) - { - Sleep(10); - } - - if (EmuWindow::GetParentWnd()) - { - // Re-stretch window to parent window size again, if it has a parent window. - RECT rcParentWindow; - GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow); - int width = rcParentWindow.right - rcParentWindow.left; - int height = rcParentWindow.bottom - rcParentWindow.top; - if (width != s_backbuffer_width || height != s_backbuffer_height) - MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE); - } - RECT rcWindow; - GetClientRect(EmuWindow::GetWnd(), &rcWindow); - int client_width = rcWindow.right - rcWindow.left; - int client_height = rcWindow.bottom - rcWindow.top; - // Sanity check. - if ((client_width != s_backbuffer_width || - client_height != s_backbuffer_height) && - client_width >= 4 && client_height >= 4) - { - TeardownDeviceObjects(); - - D3D::Reset(); - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - - return true; - } - - return false; -} - -bool Renderer::SetScissorRect() -{ - EFBRectangle rc; - if (g_renderer->SetScissorRect(rc)) - { - D3D::dev->SetScissorRect((RECT*)&rc); - return true; - } - else - { - //WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom); - const int Xstride = (s_Fulltarget_width - s_target_width) / 2; - const int Ystride = (s_Fulltarget_height - s_target_height) / 2; - rc.left = Xstride; - rc.top = Ystride; - rc.right = Xstride + s_target_width; - rc.bottom = Ystride + s_target_height; - - D3D::dev->SetScissorRect((RECT*)&rc); - return false; - } -} - -void Renderer::SetColorMask() -{ - DWORD color_mask = 0; - if (bpmem.blendmode.alphaupdate) - color_mask = D3DCOLORWRITEENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - color_mask |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; - D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); -} - -u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) -{ - if (!g_ActiveConfig.bEFBAccessEnable) - return 0; - - if (type == POKE_Z || type == POKE_COLOR) - { - static bool alert_only_once = true; - if (!alert_only_once) return 0; - PanicAlert("Poke EFB not implemented"); - alert_only_once = false; - return 0; - } - - // Get the working buffer - LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ? - FramebufferManager::GetEFBDepthRTSurface() : FramebufferManager::GetEFBColorRTSurface(); - // Get the temporal buffer to move 1pixel data - LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ? - FramebufferManager::GetEFBDepthReadSurface() : FramebufferManager::GetEFBColorReadSurface(); - // Get the memory buffer that can be locked - LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ? - FramebufferManager::GetEFBDepthOffScreenRTSurface() : FramebufferManager::GetEFBColorOffScreenRTSurface(); - // Get the buffer format - D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ? - FramebufferManager::GetEFBDepthRTSurfaceFormat() : FramebufferManager::GetEFBColorRTSurfaceFormat(); - D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ? - FramebufferManager::GetEFBDepthReadSurfaceFormat() : BufferFormat; - - if (BufferFormat == D3DFMT_D24X8) - return 0; - - D3DLOCKED_RECT drect; - - // Buffer not found alert - if (!pBuffer) { - PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB"); - return 0; - } - // Get the rectangular target region covered by the EFB pixel. - - EFBRectangle efbPixelRc; - efbPixelRc.left = x; - efbPixelRc.top = y; - efbPixelRc.right = x + 1; - efbPixelRc.bottom = y + 1; - - TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); - - u32 z = 0; - float val = 0.0f; - HRESULT hr; - RECT RectToLock; - RectToLock.bottom = targetPixelRc.bottom; - RectToLock.left = targetPixelRc.left; - RectToLock.right = targetPixelRc.right; - RectToLock.top = targetPixelRc.top; - if (type == PEEK_Z) - { - RECT PixelRect; - PixelRect.bottom = 4; - PixelRect.left = 0; - PixelRect.right = 4; - PixelRect.top = 0; - RectToLock.bottom+=2; - RectToLock.right+=1; - RectToLock.top-=1; - RectToLock.left-=2; - if ((RectToLock.bottom - RectToLock.top) > 4) - RectToLock.bottom--; - if ((RectToLock.right - RectToLock.left) > 4) - RectToLock.left++; - ResetAPIState(); // Reset any game specific settings - hr = D3D::dev->SetDepthStencilSurface(NULL); - hr = D3D::dev->SetRenderTarget(0, RBuffer); - if (FAILED(hr)) - { - PanicAlert("unable to set pixel render buffer"); - return 0; - } - D3DVIEWPORT9 vp; - // Stretch picture with increased internal resolution - vp.X = 0; - vp.Y = 0; - vp.Width = 4; - vp.Height = 4; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - hr = D3D::dev->SetViewport(&vp); - if (FAILED(hr)) - { - PanicAlert("unable to set pixel viewport"); - return 0; - } - float colmat[16] = {0.0f}; - float fConstAdd[4] = {0.0f}; - colmat[0] = colmat[5] = colmat[10] = 1.0f; - PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation - EFBRectangle source_rect; - LPDIRECT3DTEXTURE9 read_texture = FramebufferManager::GetEFBDepthTexture(source_rect); - - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - - D3D::drawShadedTexQuad( - read_texture, - &RectToLock, - Renderer::GetFullTargetWidth(), - Renderer::GetFullTargetHeight(), - 4, 4, - (BufferFormat == FOURCC_RAWZ) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0), - VertexShaderCache::GetSimpleVertexShader(0)); - - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - - hr = D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - hr = D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - RestoreAPIState(); - RectToLock.bottom = 4; - RectToLock.left = 0; - RectToLock.right = 4; - RectToLock.top = 0; - } - else - { - hr = D3D::dev->StretchRect(pBuffer, &RectToLock, RBuffer, NULL, D3DTEXF_NONE); - //change the rect to lock the entire one pixel buffer - RectToLock.bottom = 1; - RectToLock.left = 0; - RectToLock.right = 1; - RectToLock.top = 0; - } - if (FAILED(hr)) - { - PanicAlert("Unable to stretch data to buffer"); - return 0; - } - // Retrieve the pixel data to the local memory buffer - D3D::dev->GetRenderTargetData(RBuffer, pOffScreenBuffer); - if (FAILED(hr)) - { - PanicAlert("Unable to copy data to mem buffer"); - return 0; - } - - - - // The surface is good.. lock it - if ((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK) - { - PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); - return 0; - } - - switch (type) { - case PEEK_Z: - { - switch (ReadBufferFormat) - { - case D3DFMT_R32F: - val = ((float*)drect.pBits)[6]; - break; - default: - float ffrac = 1.0f/255.0f; - z = ((u32*)drect.pBits)[6]; - val = ((float)((z>>16) & 0xFF)) * ffrac; - ffrac*= 1 / 255.0f; - val += ((float)((z>>8) & 0xFF)) * ffrac; - ffrac*= 1 / 255.0f; - val += ((float)(z & 0xFF)) * ffrac; - break; - }; - z = ((u32)(val * 0xffffff)); - } - break; - - case PEEK_COLOR: - z = ((u32 *)drect.pBits)[0]; - break; - case POKE_COLOR: - - // TODO: Implement POKE_Z and POKE_COLOR - default: - break; - } - - pOffScreenBuffer->UnlockRect(); - // TODO: in RE0 this value is often off by one, which causes lighting to disappear - return z; -} - -// Called from VertexShaderManager -void Renderer::UpdateViewport() -{ - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz - const int old_fulltarget_w = s_Fulltarget_width; - const int old_fulltarget_h = s_Fulltarget_height; - - int scissorXOff = bpmem.scissorOffset.x * 2; - int scissorYOff = bpmem.scissorOffset.y * 2; - - float MValueX = Renderer::GetTargetScaleX(); - float MValueY = Renderer::GetTargetScaleY(); - - int Xstride = (s_Fulltarget_width - s_target_width) / 2; - int Ystride = (s_Fulltarget_height - s_target_height) / 2; - - D3DVIEWPORT9 vp; - - // Stretch picture with increased internal resolution - int X = (int)(ceil(xfregs.rawViewport[3] - xfregs.rawViewport[0] - (scissorXOff)) * MValueX) + Xstride; - int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride; - int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX); - int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY); - if (Width < 0) - { - X += Width; - Width*=-1; - } - if (Height < 0) - { - Y += Height; - Height *= -1; - } - bool sizeChanged = false; - if (X < 0) - { - s_Fulltarget_width -= 2 * X; - X = 0; - sizeChanged=true; - } - if (Y < 0) - { - s_Fulltarget_height -= 2 * Y; - Y = 0; - sizeChanged = true; - } - if (!IS_AMD) - { - if(X + Width > s_Fulltarget_width) - { - s_Fulltarget_width += (X + Width - s_Fulltarget_width) * 2; - sizeChanged = true; - } - if(Y + Height > s_Fulltarget_height) - { - s_Fulltarget_height += (Y + Height - s_Fulltarget_height) * 2; - sizeChanged = true; - } - } - if (sizeChanged) - { - D3DCAPS9 caps = D3D::GetCaps(); - // Make sure that the requested size is actually supported by the GFX driver - if (s_Fulltarget_width > caps.MaxTextureWidth || s_Fulltarget_height > caps.MaxTextureHeight) - { - // Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least - ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", s_Fulltarget_width, s_Fulltarget_height, old_fulltarget_w, old_fulltarget_h); - - // Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors - X *= old_fulltarget_w / s_Fulltarget_width; - Y *= old_fulltarget_h / s_Fulltarget_height; - Width *= old_fulltarget_w / s_Fulltarget_width; - Height *= old_fulltarget_h / s_Fulltarget_height; - - s_Fulltarget_width = old_fulltarget_w; - s_Fulltarget_height = old_fulltarget_h; - } - else - { - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - - delete g_framebuffer_manager; - g_framebuffer_manager = new FramebufferManager(); - - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - } - } - vp.X = X; - vp.Y = Y; - vp.Width = Width; - vp.Height = Height; - - // Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work - vp.MinZ = 0.0f; // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f; - vp.MaxZ = 1.0f; // xfregs.rawViewport[5] / 16777216.0f; - D3D::dev->SetViewport(&vp); -} - -void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) -{ - // Update the view port for clearing the picture - TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); - D3DVIEWPORT9 vp; - vp.X = targetRc.left; - vp.Y = targetRc.top; - vp.Width = targetRc.GetWidth(); - vp.Height = targetRc.GetHeight(); - vp.MinZ = 0.0; - vp.MaxZ = 1.0; - D3D::dev->SetViewport(&vp); - - // Always set the scissor in case it was set by the game and has not been reset - RECT sicr; - sicr.left = targetRc.left; - sicr.top = targetRc.top; - sicr.right = targetRc.right; - sicr.bottom = targetRc.bottom; - D3D::dev->SetScissorRect(&sicr); - D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false); - if (zEnable) - D3D::ChangeRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); - D3D::drawClearQuad(color, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader()); - if (zEnable) - D3D::RefreshRenderState(D3DRS_ZFUNC); - D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE); - UpdateViewport(); - SetScissorRect(); -} - -void Renderer::SetBlendMode(bool forceUpdate) -{ - if (bpmem.blendmode.logicopenable) - return; - - if (bpmem.blendmode.subtract && bpmem.blendmode.blendenable) - { - D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true); - D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); - D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[1]); - D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[1]); - } - else - { - D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))); - if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))) - { - D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]); - D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[bpmem.blendmode.dstfactor]); - } - } -} - -void Renderer::ResetAPIState() -{ - D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - D3D::SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - D3D::SetRenderState(D3DRS_ZENABLE, FALSE); - D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - DWORD color_mask = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; - D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); -} - -void Renderer::RestoreAPIState() -{ - // Gets us back into a more game-like state. - D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); - UpdateViewport(); - SetScissorRect(); - if (bpmem.zmode.testenable) - D3D::SetRenderState(D3DRS_ZENABLE, TRUE); - if (bpmem.zmode.updateenable) - D3D::SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - SetColorMask(); - SetLogicOpMode(); -} - -void Renderer::SetGenerationMode() -{ - D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); -} - -void Renderer::SetDepthMode() -{ - if (bpmem.zmode.testenable) - { - D3D::SetRenderState(D3DRS_ZENABLE, TRUE); - D3D::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); - D3D::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]); - } - else - { - D3D::SetRenderState(D3DRS_ZENABLE, FALSE); - D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); // ?? - } -} - -void Renderer::SetLogicOpMode() -{ - if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) - { - D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true); - D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]); - D3D::SetRenderState(D3DRS_SRCBLEND, d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]); - D3D::SetRenderState(D3DRS_DESTBLEND, d3dLogicOpDestFactors[bpmem.blendmode.logicmode]); - } - else - { - SetBlendMode(true); - } -} - -void Renderer::SetDitherMode() -{ - D3D::SetRenderState(D3DRS_DITHERENABLE, bpmem.blendmode.dither); -} - -void Renderer::SetLineWidth() -{ - // We can't change line width in D3D unless we use ID3DXLine - float fratio = xfregs.rawViewport[0] != 0 ? Renderer::GetTargetScaleX() : 1.0f; - float psize = bpmem.lineptwidth.linesize * fratio / 6.0f; - D3D::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize)); -} - -void Renderer::SetSamplerState(int stage, int texindex) -{ - const FourTexUnits &tex = bpmem.tex[texindex]; - const TexMode0 &tm0 = tex.texMode0[stage]; - const TexMode1 &tm1 = tex.texMode1[stage]; - - D3DTEXTUREFILTERTYPE min, mag, mip; - if (g_ActiveConfig.bForceFiltering) - { - min = mag = mip = D3DTEXF_LINEAR; - } - else - { - min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; - mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; - mip = (tm0.min_filter == 8) ? D3DTEXF_NONE : d3dMipFilters[tm0.min_filter & 3]; - if((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) - mip = D3DTEXF_NONE; - } - if (texindex) - stage += 4; - - if (mag == D3DTEXF_LINEAR && min == D3DTEXF_LINEAR && g_ActiveConfig.iMaxAnisotropy > 1) - { - min = D3DTEXF_ANISOTROPIC; - } - D3D::SetSamplerState(stage, D3DSAMP_MINFILTER, min); - D3D::SetSamplerState(stage, D3DSAMP_MAGFILTER, mag); - D3D::SetSamplerState(stage, D3DSAMP_MIPFILTER, mip); - - D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); - D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); - //float SuperSampleCoeficient = (s_LastAA < 3)? s_LastAA + 1 : s_LastAA - 1;// uncoment this changes to conserve detail when incresing ssaa level - float lodbias = (tm0.lod_bias / 32.0f);// + (s_LastAA)?(log(SuperSampleCoeficient) / log(2.0f)):0; - D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias); - D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4); -} - -void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect) -{ - D3D::dev->SetDepthStencilSurface(NULL); - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - - D3DVIEWPORT9 vp; - vp.X = 0; - vp.Y = 0; - vp.Width = s_backbuffer_width; - vp.Height = s_backbuffer_height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); - - int X = dst_rect.left; - int Y = dst_rect.top; - int Width = dst_rect.right - dst_rect.left; - int Height = dst_rect.bottom - dst_rect.top; - - if (X < 0) X = 0; - if (Y < 0) Y = 0; - if (X > s_backbuffer_width) X = s_backbuffer_width; - if (Y > s_backbuffer_height) Y = s_backbuffer_height; - if (Width < 0) Width = 0; - if (Height < 0) Height = 0; - if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X; - if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y; - vp.X = X; - vp.Y = Y; - vp.Width = Width; - vp.Height = Height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - - D3D::dev->SetViewport(&vp); - - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); -} - -void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) -{ - // TODO: this is lame here - TargetRectangle dst_rect; - ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); - - const int Width = dst_rect.right - dst_rect.left; - const int Height = dst_rect.bottom - dst_rect.top; - - if (xfbSource) - { - const LPDIRECT3DTEXTURE9 tex = ((XFBSource*)xfbSource)->texture; - - // TODO: - - //D3D::drawShadedTexSubQuad(tex, &sourceRc, xfbSource->texWidth, - // xfbSource->texHeight, &drawRc, Width, Height, PixelShaderCache::GetColorCopyProgram(0), - // VertexShaderCache::GetSimpleVertexShader(0)); - } - else - { - const LPDIRECT3DTEXTURE9 tex = FramebufferManager::GetEFBColorTexture(rc); - - D3D::drawShadedTexQuad(tex, sourceRc.AsRECT(), Renderer::GetFullTargetWidth(), - Renderer::GetFullTargetHeight(), Width, Height, - PixelShaderCache::GetColorCopyProgram(g_Config.iMultisampleMode), - VertexShaderCache::GetSimpleVertexShader(g_Config.iMultisampleMode)); - } - - // TODO: good here? - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); - - // TODO: this is for overlay text i think, move it elsewhere - D3DVIEWPORT9 vp; - vp.X = 0; - vp.Y = 0; - vp.Width = s_backbuffer_width; - vp.Height = s_backbuffer_height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); -} - -void Renderer::EndFrame() -{ - D3D::EndFrame(); -} - -void Renderer::Present() -{ - D3D::Present(); -} - -void Renderer::GetBackBufferSize(int* w, int* h) -{ - *w = D3D::GetBackBufferWidth(); - *h = D3D::GetBackBufferHeight(); -} - -void Renderer::RecreateFramebufferManger() -{ - // TODO: these ok here? - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - SetupDeviceObjects(); - - delete g_framebuffer_manager; - g_framebuffer_manager = new FramebufferManager; - - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); -} - -void Renderer::BeginFrame() -{ - D3D::BeginFrame(); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include +#include + +#include "StringUtil.h" +#include "Common.h" +#include "Atomic.h" +#include "FileUtil.h" +#include "Thread.h" +#include "Timer.h" +#include "Statistics.h" + +#include "VideoConfig.h" +#include "main.h" +#include "DX9_VertexManager.h" +#include "DX9_Render.h" +#include "OpcodeDecoding.h" +#include "BPStructs.h" +#include "XFStructs.h" +#include "DX9_D3DUtil.h" +#include "VertexShaderManager.h" +#include "PixelShaderManager.h" +#include "DX9_VertexShaderCache.h" +#include "DX9_PixelShaderCache.h" +#include "VertexLoaderManager.h" +#include "DX9_TextureCache.h" +#include "EmuWindow.h" +#include "AVIDump.h" +#include "OnScreenDisplay.h" +#include "DX9_FramebufferManager.h" +#include "Fifo.h" +#include "DX9_TextureConverter.h" +#include "DLCache.h" + +//#include "debugger/debugger.h" + +#include "DX9_Render.h" + +namespace DX9 +{ + +bool Renderer::IS_AMD; + +// State translation lookup tables +static const D3DBLEND d3dSrcFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_DESTCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + +static const D3DBLEND d3dDestFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_SRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + +static const D3DBLENDOP d3dLogicOpop[16] = +{ + D3DBLENDOP_ADD, + D3DBLENDOP_ADD, + D3DBLENDOP_SUBTRACT, + D3DBLENDOP_ADD, + D3DBLENDOP_REVSUBTRACT, + D3DBLENDOP_ADD, + D3DBLENDOP_MAX, + D3DBLENDOP_ADD, + + D3DBLENDOP_MAX, + D3DBLENDOP_MAX, + D3DBLENDOP_ADD, + D3DBLENDOP_ADD, + D3DBLENDOP_ADD, + D3DBLENDOP_ADD, + D3DBLENDOP_ADD, + D3DBLENDOP_ADD +}; + +static const D3DBLEND d3dLogicOpSrcFactors[16] = +{ + D3DBLEND_ZERO, + D3DBLEND_DESTCOLOR, + D3DBLEND_ONE, + D3DBLEND_ONE, + D3DBLEND_DESTCOLOR, + D3DBLEND_ZERO, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_INVDESTCOLOR, + + D3DBLEND_INVSRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_ONE, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_ONE +}; + +static const D3DBLEND d3dLogicOpDestFactors[16] = +{ + D3DBLEND_ZERO, + D3DBLEND_ZERO, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_ONE, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_ONE, + + D3DBLEND_INVDESTCOLOR, + D3DBLEND_SRCCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_ONE, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_ONE +}; + +static const D3DCULL d3dCullModes[4] = +{ + D3DCULL_NONE, + D3DCULL_CCW, + D3DCULL_CW, + D3DCULL_CCW +}; + +static const D3DCMPFUNC d3dCmpFuncs[8] = +{ + D3DCMP_NEVER, + D3DCMP_LESS, + D3DCMP_EQUAL, + D3DCMP_LESSEQUAL, + D3DCMP_GREATER, + D3DCMP_NOTEQUAL, + D3DCMP_GREATEREQUAL, + D3DCMP_ALWAYS +}; + +static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] = +{ + D3DTEXF_NONE, + D3DTEXF_POINT, + D3DTEXF_LINEAR, + D3DTEXF_NONE, //reserved +}; + +static const D3DTEXTUREADDRESS d3dClamps[4] = +{ + D3DTADDRESS_CLAMP, + D3DTADDRESS_WRAP, + D3DTADDRESS_MIRROR, + D3DTADDRESS_WRAP //reserved +}; + +void Renderer::SetupDeviceObjects() +{ + D3D::font.Init(); + g_framebuffer_manager = new FramebufferManager; + + VertexShaderManager::Dirty(); + PixelShaderManager::Dirty(); + // TODO: + //TextureConverter::Init(); + + // To avoid shader compilation stutters, read back all shaders from cache. + // Texture cache will recreate themselves over time. +} + +// Kill off all POOL_DEFAULT device objects. +void Renderer::TeardownDeviceObjects() +{ + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); + + delete g_framebuffer_manager; + + //D3D::font.Shutdown(); + // TODO: + //TextureConverter::Shutdown(); +} + +Renderer::Renderer() +{ + UpdateActiveConfig(); + int fullScreenRes, x, y, w_temp, h_temp; + s_blendMode = 0; + // Multisample Anti-aliasing hasn't been implemented yet use supersamling instead + int backbuffer_ms_mode = 0; + + g_VideoInitialize.pRequestWindowSize(x, y, w_temp, h_temp); + + for (fullScreenRes = 0; fullScreenRes < (int)D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size(); fullScreenRes++) + { + if ((D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].xres == w_temp) && + (D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions[fullScreenRes].yres == h_temp)) + break; + } + if (fullScreenRes == D3D::GetAdapter(g_ActiveConfig.iAdapter).resolutions.size()) + fullScreenRes = 0; + + D3D::Init(); + + D3D::Create(g_ActiveConfig.iAdapter, EmuWindow::GetWnd(), + fullScreenRes, backbuffer_ms_mode, false); + + IS_AMD = D3D::IsATIDevice(); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + + s_XFB_width = MAX_XFB_WIDTH; + s_XFB_height = MAX_XFB_HEIGHT; + + FramebufferSize(s_backbuffer_width, s_backbuffer_height); + + // We're not using fixed function. + // Let's just set the matrices to identity to be sure. + D3DXMATRIX mtx; + D3DXMatrixIdentity(&mtx); + D3D::dev->SetTransform(D3DTS_VIEW, &mtx); + D3D::dev->SetTransform(D3DTS_WORLD, &mtx); + + SetupDeviceObjects(); + + for (int stage = 0; stage < 8; stage++) + D3D::SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, g_ActiveConfig.iMaxAnisotropy); + + D3DVIEWPORT9 vp; + vp.X = 0; + vp.Y = 0; + vp.Width = s_backbuffer_width; + vp.Height = s_backbuffer_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, 0x0, 0, 0); + + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + vp.X = (s_Fulltarget_width - s_target_width) / 2; + vp.Y = (s_Fulltarget_height - s_target_height) / 2; + vp.Width = s_target_width; + vp.Height = s_target_height; + D3D::dev->SetViewport(&vp); + D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0); + D3D::BeginFrame(); + D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true); + //return true; +} + +Renderer::~Renderer() +{ + TeardownDeviceObjects(); + D3D::EndFrame(); + D3D::Present(); + D3D::Close(); +} + +void formatBufferDump(const char *in, char *out, int w, int h, int p) +{ + for (int y = 0; y < h; y++) + { + const char *line = in + (h - y - 1) * p; + for (int x = 0; x < w; x++) + { + memcpy(out, line, 3); + out += 3; + line += 4; + } + } +} + +// With D3D, we have to resize the backbuffer if the window changed +// size. +bool Renderer::CheckForResize() +{ + while (EmuWindow::IsSizing()) + { + Sleep(10); + } + + if (EmuWindow::GetParentWnd()) + { + // Re-stretch window to parent window size again, if it has a parent window. + RECT rcParentWindow; + GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow); + int width = rcParentWindow.right - rcParentWindow.left; + int height = rcParentWindow.bottom - rcParentWindow.top; + if (width != s_backbuffer_width || height != s_backbuffer_height) + MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE); + } + RECT rcWindow; + GetClientRect(EmuWindow::GetWnd(), &rcWindow); + int client_width = rcWindow.right - rcWindow.left; + int client_height = rcWindow.bottom - rcWindow.top; + // Sanity check. + if ((client_width != s_backbuffer_width || + client_height != s_backbuffer_height) && + client_width >= 4 && client_height >= 4) + { + TeardownDeviceObjects(); + + D3D::Reset(); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + + return true; + } + + return false; +} + +bool Renderer::SetScissorRect() +{ + EFBRectangle rc; + if (g_renderer->SetScissorRect(rc)) + { + D3D::dev->SetScissorRect((RECT*)&rc); + return true; + } + else + { + //WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom); + const int Xstride = (s_Fulltarget_width - s_target_width) / 2; + const int Ystride = (s_Fulltarget_height - s_target_height) / 2; + rc.left = Xstride; + rc.top = Ystride; + rc.right = Xstride + s_target_width; + rc.bottom = Ystride + s_target_height; + + D3D::dev->SetScissorRect((RECT*)&rc); + return false; + } +} + +void Renderer::SetColorMask() +{ + DWORD color_mask = 0; + if (bpmem.blendmode.alphaupdate) + color_mask = D3DCOLORWRITEENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + color_mask |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; + D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); +} + +u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +{ + if (!g_ActiveConfig.bEFBAccessEnable) + return 0; + + if (type == POKE_Z || type == POKE_COLOR) + { + static bool alert_only_once = true; + if (!alert_only_once) return 0; + PanicAlert("Poke EFB not implemented"); + alert_only_once = false; + return 0; + } + + // Get the working buffer + LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ? + FramebufferManager::GetEFBDepthRTSurface() : FramebufferManager::GetEFBColorRTSurface(); + // Get the temporal buffer to move 1pixel data + LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ? + FramebufferManager::GetEFBDepthReadSurface() : FramebufferManager::GetEFBColorReadSurface(); + // Get the memory buffer that can be locked + LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ? + FramebufferManager::GetEFBDepthOffScreenRTSurface() : FramebufferManager::GetEFBColorOffScreenRTSurface(); + // Get the buffer format + D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ? + FramebufferManager::GetEFBDepthRTSurfaceFormat() : FramebufferManager::GetEFBColorRTSurfaceFormat(); + D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ? + FramebufferManager::GetEFBDepthReadSurfaceFormat() : BufferFormat; + + if (BufferFormat == D3DFMT_D24X8) + return 0; + + D3DLOCKED_RECT drect; + + // Buffer not found alert + if (!pBuffer) { + PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB"); + return 0; + } + // Get the rectangular target region covered by the EFB pixel. + + EFBRectangle efbPixelRc; + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + + TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); + + u32 z = 0; + float val = 0.0f; + HRESULT hr; + RECT RectToLock; + RectToLock.bottom = targetPixelRc.bottom; + RectToLock.left = targetPixelRc.left; + RectToLock.right = targetPixelRc.right; + RectToLock.top = targetPixelRc.top; + if (type == PEEK_Z) + { + RECT PixelRect; + PixelRect.bottom = 4; + PixelRect.left = 0; + PixelRect.right = 4; + PixelRect.top = 0; + RectToLock.bottom+=2; + RectToLock.right+=1; + RectToLock.top-=1; + RectToLock.left-=2; + if ((RectToLock.bottom - RectToLock.top) > 4) + RectToLock.bottom--; + if ((RectToLock.right - RectToLock.left) > 4) + RectToLock.left++; + ResetAPIState(); // Reset any game specific settings + hr = D3D::dev->SetDepthStencilSurface(NULL); + hr = D3D::dev->SetRenderTarget(0, RBuffer); + if (FAILED(hr)) + { + PanicAlert("unable to set pixel render buffer"); + return 0; + } + D3DVIEWPORT9 vp; + // Stretch picture with increased internal resolution + vp.X = 0; + vp.Y = 0; + vp.Width = 4; + vp.Height = 4; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + hr = D3D::dev->SetViewport(&vp); + if (FAILED(hr)) + { + PanicAlert("unable to set pixel viewport"); + return 0; + } + float colmat[16] = {0.0f}; + float fConstAdd[4] = {0.0f}; + colmat[0] = colmat[5] = colmat[10] = 1.0f; + PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation + EFBRectangle source_rect; + LPDIRECT3DTEXTURE9 read_texture = FramebufferManager::GetEFBDepthTexture(source_rect); + + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + + D3D::drawShadedTexQuad( + read_texture, + &RectToLock, + Renderer::GetFullTargetWidth(), + Renderer::GetFullTargetHeight(), + 4, 4, + (BufferFormat == FOURCC_RAWZ) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0), + VertexShaderCache::GetSimpleVertexShader(0)); + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + + hr = D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + hr = D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + RestoreAPIState(); + RectToLock.bottom = 4; + RectToLock.left = 0; + RectToLock.right = 4; + RectToLock.top = 0; + } + else + { + hr = D3D::dev->StretchRect(pBuffer, &RectToLock, RBuffer, NULL, D3DTEXF_NONE); + //change the rect to lock the entire one pixel buffer + RectToLock.bottom = 1; + RectToLock.left = 0; + RectToLock.right = 1; + RectToLock.top = 0; + } + if (FAILED(hr)) + { + PanicAlert("Unable to stretch data to buffer"); + return 0; + } + // Retrieve the pixel data to the local memory buffer + D3D::dev->GetRenderTargetData(RBuffer, pOffScreenBuffer); + if (FAILED(hr)) + { + PanicAlert("Unable to copy data to mem buffer"); + return 0; + } + + + + // The surface is good.. lock it + if ((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK) + { + PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); + return 0; + } + + switch (type) { + case PEEK_Z: + { + switch (ReadBufferFormat) + { + case D3DFMT_R32F: + val = ((float*)drect.pBits)[6]; + break; + default: + float ffrac = 1.0f/255.0f; + z = ((u32*)drect.pBits)[6]; + val = ((float)((z>>16) & 0xFF)) * ffrac; + ffrac*= 1 / 255.0f; + val += ((float)((z>>8) & 0xFF)) * ffrac; + ffrac*= 1 / 255.0f; + val += ((float)(z & 0xFF)) * ffrac; + break; + }; + z = ((u32)(val * 0xffffff)); + } + break; + + case PEEK_COLOR: + z = ((u32 *)drect.pBits)[0]; + break; + case POKE_COLOR: + + // TODO: Implement POKE_Z and POKE_COLOR + default: + break; + } + + pOffScreenBuffer->UnlockRect(); + // TODO: in RE0 this value is often off by one, which causes lighting to disappear + return z; +} + +// Called from VertexShaderManager +void Renderer::UpdateViewport() +{ + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz + const int old_fulltarget_w = s_Fulltarget_width; + const int old_fulltarget_h = s_Fulltarget_height; + + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; + + float MValueX = Renderer::GetTargetScaleX(); + float MValueY = Renderer::GetTargetScaleY(); + + int Xstride = (s_Fulltarget_width - s_target_width) / 2; + int Ystride = (s_Fulltarget_height - s_target_height) / 2; + + D3DVIEWPORT9 vp; + + // Stretch picture with increased internal resolution + int X = (int)(ceil(xfregs.rawViewport[3] - xfregs.rawViewport[0] - (scissorXOff)) * MValueX) + Xstride; + int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride; + int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX); + int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY); + if (Width < 0) + { + X += Width; + Width*=-1; + } + if (Height < 0) + { + Y += Height; + Height *= -1; + } + bool sizeChanged = false; + if (X < 0) + { + s_Fulltarget_width -= 2 * X; + X = 0; + sizeChanged=true; + } + if (Y < 0) + { + s_Fulltarget_height -= 2 * Y; + Y = 0; + sizeChanged = true; + } + if (!IS_AMD) + { + if(X + Width > s_Fulltarget_width) + { + s_Fulltarget_width += (X + Width - s_Fulltarget_width) * 2; + sizeChanged = true; + } + if(Y + Height > s_Fulltarget_height) + { + s_Fulltarget_height += (Y + Height - s_Fulltarget_height) * 2; + sizeChanged = true; + } + } + if (sizeChanged) + { + D3DCAPS9 caps = D3D::GetCaps(); + // Make sure that the requested size is actually supported by the GFX driver + if (s_Fulltarget_width > caps.MaxTextureWidth || s_Fulltarget_height > caps.MaxTextureHeight) + { + // Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least + ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", s_Fulltarget_width, s_Fulltarget_height, old_fulltarget_w, old_fulltarget_h); + + // Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors + X *= old_fulltarget_w / s_Fulltarget_width; + Y *= old_fulltarget_h / s_Fulltarget_height; + Width *= old_fulltarget_w / s_Fulltarget_width; + Height *= old_fulltarget_h / s_Fulltarget_height; + + s_Fulltarget_width = old_fulltarget_w; + s_Fulltarget_height = old_fulltarget_h; + } + else + { + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); + + delete g_framebuffer_manager; + g_framebuffer_manager = new FramebufferManager(); + + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + } + } + vp.X = X; + vp.Y = Y; + vp.Width = Width; + vp.Height = Height; + + // Some games set invalids values for z min and z max so fix them to the max an min alowed and let the shaders do this work + vp.MinZ = 0.0f; // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f; + vp.MaxZ = 1.0f; // xfregs.rawViewport[5] / 16777216.0f; + D3D::dev->SetViewport(&vp); +} + +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +{ + // Update the view port for clearing the picture + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); + D3DVIEWPORT9 vp; + vp.X = targetRc.left; + vp.Y = targetRc.top; + vp.Width = targetRc.GetWidth(); + vp.Height = targetRc.GetHeight(); + vp.MinZ = 0.0; + vp.MaxZ = 1.0; + D3D::dev->SetViewport(&vp); + + // Always set the scissor in case it was set by the game and has not been reset + RECT sicr; + sicr.left = targetRc.left; + sicr.top = targetRc.top; + sicr.right = targetRc.right; + sicr.bottom = targetRc.bottom; + D3D::dev->SetScissorRect(&sicr); + D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false); + if (zEnable) + D3D::ChangeRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + D3D::drawClearQuad(color, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader()); + if (zEnable) + D3D::RefreshRenderState(D3DRS_ZFUNC); + D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE); + UpdateViewport(); + SetScissorRect(); +} + +void Renderer::SetBlendMode(bool forceUpdate) +{ + if (bpmem.blendmode.logicopenable) + return; + + if (bpmem.blendmode.subtract && bpmem.blendmode.blendenable) + { + D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true); + D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); + D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[1]); + D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[1]); + } + else + { + D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))); + if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0))) + { + D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]); + D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[bpmem.blendmode.dstfactor]); + } + } +} + +void Renderer::ResetAPIState() +{ + D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + D3D::SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + D3D::SetRenderState(D3DRS_ZENABLE, FALSE); + D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + DWORD color_mask = D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE; + D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); +} + +void Renderer::RestoreAPIState() +{ + // Gets us back into a more game-like state. + D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + UpdateViewport(); + SetScissorRect(); + if (bpmem.zmode.testenable) + D3D::SetRenderState(D3DRS_ZENABLE, TRUE); + if (bpmem.zmode.updateenable) + D3D::SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + SetColorMask(); + SetLogicOpMode(); +} + +void Renderer::SetGenerationMode() +{ + D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]); +} + +void Renderer::SetDepthMode() +{ + if (bpmem.zmode.testenable) + { + D3D::SetRenderState(D3DRS_ZENABLE, TRUE); + D3D::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable); + D3D::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]); + } + else + { + D3D::SetRenderState(D3DRS_ZENABLE, FALSE); + D3D::SetRenderState(D3DRS_ZWRITEENABLE, FALSE); // ?? + } +} + +void Renderer::SetLogicOpMode() +{ + if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) + { + D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true); + D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]); + D3D::SetRenderState(D3DRS_SRCBLEND, d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]); + D3D::SetRenderState(D3DRS_DESTBLEND, d3dLogicOpDestFactors[bpmem.blendmode.logicmode]); + } + else + { + SetBlendMode(true); + } +} + +void Renderer::SetDitherMode() +{ + D3D::SetRenderState(D3DRS_DITHERENABLE, bpmem.blendmode.dither); +} + +void Renderer::SetLineWidth() +{ + // We can't change line width in D3D unless we use ID3DXLine + float fratio = xfregs.rawViewport[0] != 0 ? Renderer::GetTargetScaleX() : 1.0f; + float psize = bpmem.lineptwidth.linesize * fratio / 6.0f; + D3D::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize)); +} + +void Renderer::SetSamplerState(int stage, int texindex) +{ + const FourTexUnits &tex = bpmem.tex[texindex]; + const TexMode0 &tm0 = tex.texMode0[stage]; + const TexMode1 &tm1 = tex.texMode1[stage]; + + D3DTEXTUREFILTERTYPE min, mag, mip; + if (g_ActiveConfig.bForceFiltering) + { + min = mag = mip = D3DTEXF_LINEAR; + } + else + { + min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT; + mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT; + mip = (tm0.min_filter == 8) ? D3DTEXF_NONE : d3dMipFilters[tm0.min_filter & 3]; + if((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) + mip = D3DTEXF_NONE; + } + if (texindex) + stage += 4; + + if (mag == D3DTEXF_LINEAR && min == D3DTEXF_LINEAR && g_ActiveConfig.iMaxAnisotropy > 1) + { + min = D3DTEXF_ANISOTROPIC; + } + D3D::SetSamplerState(stage, D3DSAMP_MINFILTER, min); + D3D::SetSamplerState(stage, D3DSAMP_MAGFILTER, mag); + D3D::SetSamplerState(stage, D3DSAMP_MIPFILTER, mip); + + D3D::SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]); + D3D::SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]); + //float SuperSampleCoeficient = (s_LastAA < 3)? s_LastAA + 1 : s_LastAA - 1;// uncoment this changes to conserve detail when incresing ssaa level + float lodbias = (tm0.lod_bias / 32.0f);// + (s_LastAA)?(log(SuperSampleCoeficient) / log(2.0f)):0; + D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias); + D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4); +} + +void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect) +{ + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + + D3DVIEWPORT9 vp; + vp.X = 0; + vp.Y = 0; + vp.Width = s_backbuffer_width; + vp.Height = s_backbuffer_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + + int X = dst_rect.left; + int Y = dst_rect.top; + int Width = dst_rect.right - dst_rect.left; + int Height = dst_rect.bottom - dst_rect.top; + + if (X < 0) X = 0; + if (Y < 0) Y = 0; + if (X > s_backbuffer_width) X = s_backbuffer_width; + if (Y > s_backbuffer_height) Y = s_backbuffer_height; + if (Width < 0) Width = 0; + if (Height < 0) Height = 0; + if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X; + if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y; + vp.X = X; + vp.Y = Y; + vp.Width = Width; + vp.Height = Height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + + D3D::dev->SetViewport(&vp); + + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); +} + +void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) +{ + // TODO: this is lame here + TargetRectangle dst_rect; + ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); + + const int Width = dst_rect.right - dst_rect.left; + const int Height = dst_rect.bottom - dst_rect.top; + + if (xfbSource) + { + const LPDIRECT3DTEXTURE9 tex = ((XFBSource*)xfbSource)->texture; + + // TODO: + + //D3D::drawShadedTexSubQuad(tex, &sourceRc, xfbSource->texWidth, + // xfbSource->texHeight, &drawRc, Width, Height, PixelShaderCache::GetColorCopyProgram(0), + // VertexShaderCache::GetSimpleVertexShader(0)); + } + else + { + const LPDIRECT3DTEXTURE9 tex = FramebufferManager::GetEFBColorTexture(rc); + + D3D::drawShadedTexQuad(tex, sourceRc.AsRECT(), Renderer::GetFullTargetWidth(), + Renderer::GetFullTargetHeight(), Width, Height, + PixelShaderCache::GetColorCopyProgram(g_Config.iMultisampleMode), + VertexShaderCache::GetSimpleVertexShader(g_Config.iMultisampleMode)); + } + + // TODO: good here? + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + + // TODO: this is for overlay text i think, move it elsewhere + D3DVIEWPORT9 vp; + vp.X = 0; + vp.Y = 0; + vp.Width = s_backbuffer_width; + vp.Height = s_backbuffer_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); +} + +void Renderer::EndFrame() +{ + D3D::EndFrame(); +} + +void Renderer::Present() +{ + D3D::Present(); +} + +void Renderer::GetBackBufferSize(int* w, int* h) +{ + *w = D3D::GetBackBufferWidth(); + *h = D3D::GetBackBufferHeight(); +} + +void Renderer::RecreateFramebufferManger() +{ + // TODO: these ok here? + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); + SetupDeviceObjects(); + + delete g_framebuffer_manager; + g_framebuffer_manager = new FramebufferManager; + + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); +} + +void Renderer::BeginFrame() +{ + D3D::BeginFrame(); + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.h index 2d63e66fce..4b93a2fd66 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_Render.h @@ -1,58 +1,58 @@ - -#pragma once - -#include "MathUtil.h" - -#include "VideoCommon.h" -#include "Renderer.h" -#include "pluginspecs_video.h" - -namespace DX9 -{ - -class Renderer : public ::RendererBase -{ -public: - Renderer(); - ~Renderer(); - - void ResetAPIState(); - void RestoreAPIState(); - - static void SetupDeviceObjects(); - static void TeardownDeviceObjects(); - - void SetColorMask(); - void SetBlendMode(bool forceUpdate); - bool SetScissorRect(); - - void SetGenerationMode(); - void SetDepthMode(); - void SetLogicOpMode(); - void SetSamplerState(int stage,int texindex); - void SetDitherMode(); - void SetLineWidth(); - - u32 AccessEFB(EFBAccessType type, int x, int y); - - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); - void UpdateViewport(); - - // virtual funcs used by RendererBase::Swap - void PrepareXFBCopy(const TargetRectangle &dst_rect); - void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); - void EndFrame(); - void Present(); - bool CheckForResize(); - void GetBackBufferSize(int* w, int* h); - void RecreateFramebufferManger(); - void BeginFrame(); - - void Swap(u32, FieldType, u32, u32, const EFBRectangle&); - -private: - static bool IS_AMD; -}; - -} + +#pragma once + +#include "MathUtil.h" + +#include "VideoCommon.h" +#include "Renderer.h" +#include "pluginspecs_video.h" + +namespace DX9 +{ + +class Renderer : public ::RendererBase +{ +public: + Renderer(); + ~Renderer(); + + void ResetAPIState(); + void RestoreAPIState(); + + static void SetupDeviceObjects(); + static void TeardownDeviceObjects(); + + void SetColorMask(); + void SetBlendMode(bool forceUpdate); + bool SetScissorRect(); + + void SetGenerationMode(); + void SetDepthMode(); + void SetLogicOpMode(); + void SetSamplerState(int stage,int texindex); + void SetDitherMode(); + void SetLineWidth(); + + u32 AccessEFB(EFBAccessType type, int x, int y); + + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); + void UpdateViewport(); + + // virtual funcs used by RendererBase::Swap + void PrepareXFBCopy(const TargetRectangle &dst_rect); + void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); + void EndFrame(); + void Present(); + bool CheckForResize(); + void GetBackBufferSize(int* w, int* h); + void RecreateFramebufferManger(); + void BeginFrame(); + + void Swap(u32, FieldType, u32, u32, const EFBRectangle&); + +private: + static bool IS_AMD; +}; + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.cpp index 907aad6445..d57271e5b7 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.cpp @@ -1,207 +1,207 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "Statistics.h" -#include "MemoryUtil.h" -#include "Hash.h" - -#include "CommonPaths.h" -#include "FileUtil.h" - -#include "DX9_D3DBase.h" -#include "DX9_D3DTexture.h" -#include "DX9_D3DUtil.h" -#include "DX9_FramebufferManager.h" -#include "DX9_PixelShaderCache.h" -#include "PixelShaderManager.h" -#include "VertexShaderManager.h" -#include "DX9_VertexShaderCache.h" -#include "VideoConfig.h" - -#include "DX9_Render.h" - -#include "TextureDecoder.h" -#include "DX9_TextureCache.h" -#include "HiresTextures.h" -#include "DX9_TextureConverter.h" - -#include "../Main.h" - -//#include "debugger/debugger.h" - -namespace DX9 -{ - -TextureCache::TCacheEntry::TCacheEntry(LPDIRECT3DTEXTURE9 _texture) - : texture(_texture), isDynamic(false) -{ - -} - -TextureCache::TCacheEntry::~TCacheEntry() -{ - texture->Release(); -} - -void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) -{ - D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level); -} - -void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) -{ - LPDIRECT3DSURFACE9 Rendersurf = NULL; - texture->GetSurfaceLevel(0, &Rendersurf); - D3D::dev->SetDepthStencilSurface(NULL); - D3D::dev->SetRenderTarget(0, Rendersurf); - - D3DVIEWPORT9 vp; - - // Stretch picture with increased internal resolution - vp.X = 0; - vp.Y = 0; - vp.Width = Scaledw; - vp.Height = Scaledh; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - RECT destrect; - destrect.bottom = Scaledh; - destrect.left = 0; - destrect.right = Scaledw; - destrect.top = 0; - - const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat - PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation - TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect); - RECT sourcerect; - sourcerect.bottom = targetSource.bottom; - sourcerect.left = targetSource.left; - sourcerect.right = targetSource.right; - sourcerect.top = targetSource.top; - - if (bFromZBuffer) - { - if (bScaleByHalf || g_ActiveConfig.iMultisampleMode) - { - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - else - { - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - } - } - else - { - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - const LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? - FramebufferManager::GetEFBDepthTexture(source_rect) : - FramebufferManager::GetEFBColorTexture(source_rect); - - D3DFORMAT bformat = FramebufferManager::GetEFBDepthRTSurfaceFormat(); - int SSAAMode = g_ActiveConfig.iMultisampleMode; - - D3D::drawShadedTexQuad(read_texture, &sourcerect, - Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), - Scaledw, Scaledh, - ((bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8) && bFromZBuffer) ? - PixelShaderCache::GetDepthMatrixProgram(SSAAMode) : - PixelShaderCache::GetColorMatrixProgram(SSAAMode), - VertexShaderCache::GetSimpleVertexShader(SSAAMode)); - - Rendersurf->Release(); - - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); - D3D::SetTexture(0,NULL); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); -} - -void TextureCache::TCacheEntry::Bind(unsigned int stage) -{ - D3D::SetTexture(stage, texture); -} - -TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) -{ - D3DFORMAT d3d_fmt; - bool swap_r_b = false; - - switch (pcfmt) - { - case PC_TEX_FMT_BGRA32: - d3d_fmt = D3DFMT_A8R8G8B8; - break; - - case PC_TEX_FMT_RGBA32: - d3d_fmt = D3DFMT_A8R8G8B8; - swap_r_b = true; - break; - - case PC_TEX_FMT_RGB565: - d3d_fmt = D3DFMT_R5G6B5; - break; - - case PC_TEX_FMT_IA4_AS_IA8: - d3d_fmt = D3DFMT_A8L8; - break; - - case PC_TEX_FMT_I8: - case PC_TEX_FMT_I4_AS_I8: - // A hack which means the format is a packed - // 8-bit intensity texture. It is unpacked - // to A8L8 in D3DTexture.cpp - d3d_fmt = D3DFMT_A8P8; - break; - - case PC_TEX_FMT_IA8: - d3d_fmt = D3DFMT_A8L8; - break; - - case PC_TEX_FMT_DXT1: - d3d_fmt = D3DFMT_DXT1; - break; - } - - TCacheEntry* entry = new TCacheEntry(D3D::CreateTexture2D(temp, width, height, expanded_width, d3d_fmt, swap_r_b, tex_levels)); - entry->swap_r_b = swap_r_b; - entry->d3d_fmt = d3d_fmt; - - return entry; -} - -TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) -{ - LPDIRECT3DTEXTURE9 texture; - D3D::dev->CreateTexture(scaled_tex_w, scaled_tex_h, 1, D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, 0); - - return new TCacheEntry(texture); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "Statistics.h" +#include "MemoryUtil.h" +#include "Hash.h" + +#include "CommonPaths.h" +#include "FileUtil.h" + +#include "DX9_D3DBase.h" +#include "DX9_D3DTexture.h" +#include "DX9_D3DUtil.h" +#include "DX9_FramebufferManager.h" +#include "DX9_PixelShaderCache.h" +#include "PixelShaderManager.h" +#include "VertexShaderManager.h" +#include "DX9_VertexShaderCache.h" +#include "VideoConfig.h" + +#include "DX9_Render.h" + +#include "TextureDecoder.h" +#include "DX9_TextureCache.h" +#include "HiresTextures.h" +#include "DX9_TextureConverter.h" + +#include "../Main.h" + +//#include "debugger/debugger.h" + +namespace DX9 +{ + +TextureCache::TCacheEntry::TCacheEntry(LPDIRECT3DTEXTURE9 _texture) + : texture(_texture), isDynamic(false) +{ + +} + +TextureCache::TCacheEntry::~TCacheEntry() +{ + texture->Release(); +} + +void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level) +{ + D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level); +} + +void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) +{ + LPDIRECT3DSURFACE9 Rendersurf = NULL; + texture->GetSurfaceLevel(0, &Rendersurf); + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, Rendersurf); + + D3DVIEWPORT9 vp; + + // Stretch picture with increased internal resolution + vp.X = 0; + vp.Y = 0; + vp.Width = Scaledw; + vp.Height = Scaledh; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + RECT destrect; + destrect.bottom = Scaledh; + destrect.left = 0; + destrect.right = Scaledw; + destrect.top = 0; + + const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat + PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation + TargetRectangle targetSource = Renderer::ConvertEFBRectangle(source_rect); + RECT sourcerect; + sourcerect.bottom = targetSource.bottom; + sourcerect.left = targetSource.left; + sourcerect.right = targetSource.right; + sourcerect.top = targetSource.top; + + if (bFromZBuffer) + { + if (bScaleByHalf || g_ActiveConfig.iMultisampleMode) + { + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + else + { + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + } + } + else + { + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + const LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? + FramebufferManager::GetEFBDepthTexture(source_rect) : + FramebufferManager::GetEFBColorTexture(source_rect); + + D3DFORMAT bformat = FramebufferManager::GetEFBDepthRTSurfaceFormat(); + int SSAAMode = g_ActiveConfig.iMultisampleMode; + + D3D::drawShadedTexQuad(read_texture, &sourcerect, + Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), + Scaledw, Scaledh, + ((bformat != FOURCC_RAWZ && bformat != D3DFMT_D24X8) && bFromZBuffer) ? + PixelShaderCache::GetDepthMatrixProgram(SSAAMode) : + PixelShaderCache::GetColorMatrixProgram(SSAAMode), + VertexShaderCache::GetSimpleVertexShader(SSAAMode)); + + Rendersurf->Release(); + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + D3D::SetTexture(0,NULL); + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); +} + +void TextureCache::TCacheEntry::Bind(unsigned int stage) +{ + D3D::SetTexture(stage, texture); +} + +TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) +{ + D3DFORMAT d3d_fmt; + bool swap_r_b = false; + + switch (pcfmt) + { + case PC_TEX_FMT_BGRA32: + d3d_fmt = D3DFMT_A8R8G8B8; + break; + + case PC_TEX_FMT_RGBA32: + d3d_fmt = D3DFMT_A8R8G8B8; + swap_r_b = true; + break; + + case PC_TEX_FMT_RGB565: + d3d_fmt = D3DFMT_R5G6B5; + break; + + case PC_TEX_FMT_IA4_AS_IA8: + d3d_fmt = D3DFMT_A8L8; + break; + + case PC_TEX_FMT_I8: + case PC_TEX_FMT_I4_AS_I8: + // A hack which means the format is a packed + // 8-bit intensity texture. It is unpacked + // to A8L8 in D3DTexture.cpp + d3d_fmt = D3DFMT_A8P8; + break; + + case PC_TEX_FMT_IA8: + d3d_fmt = D3DFMT_A8L8; + break; + + case PC_TEX_FMT_DXT1: + d3d_fmt = D3DFMT_DXT1; + break; + } + + TCacheEntry* entry = new TCacheEntry(D3D::CreateTexture2D(temp, width, height, expanded_width, d3d_fmt, swap_r_b, tex_levels)); + entry->swap_r_b = swap_r_b; + entry->d3d_fmt = d3d_fmt; + + return entry; +} + +TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) +{ + LPDIRECT3DTEXTURE9 texture; + D3D::dev->CreateTexture(scaled_tex_w, scaled_tex_h, 1, D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, 0); + + return new TCacheEntry(texture); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.h index ba35502816..dbfe4b1b0e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureCache.h @@ -1,67 +1,67 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _TEXTURECACHE_H -#define _TEXTURECACHE_H - - -#include - -#include "DX9_D3DBase.h" -#include "VideoCommon.h" -#include "BPMemory.h" - -#include "../TextureCache.h" - -namespace DX9 -{ - -class TextureCache : public TextureCacheBase -{ -public: - struct TCacheEntry : TCacheEntryBase - { - LPDIRECT3DTEXTURE9 texture; - - D3DFORMAT d3d_fmt; - bool swap_r_b; - bool isDynamic; // mofified from cpu - - TCacheEntry(LPDIRECT3DTEXTURE9 _texture); - ~TCacheEntry(); - - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int levels); - - void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); - - void Bind(unsigned int stage); - }; - -public: - - TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); - - TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); - -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _TEXTURECACHE_H +#define _TEXTURECACHE_H + + +#include + +#include "DX9_D3DBase.h" +#include "VideoCommon.h" +#include "BPMemory.h" + +#include "../TextureCache.h" + +namespace DX9 +{ + +class TextureCache : public TextureCacheBase +{ +public: + struct TCacheEntry : TCacheEntryBase + { + LPDIRECT3DTEXTURE9 texture; + + D3DFORMAT d3d_fmt; + bool swap_r_b; + bool isDynamic; // mofified from cpu + + TCacheEntry(LPDIRECT3DTEXTURE9 _texture); + ~TCacheEntry(); + + void Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int levels); + + void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); + + void Bind(unsigned int stage); + }; + +public: + + TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); + + TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); + +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.cpp index b38aefe73b..9d3c0f88e7 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.cpp @@ -1,560 +1,560 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Fast image conversion using OpenGL shaders. -// This kind of stuff would be a LOT nicer with OpenCL. - -#include "DX9_TextureConverter.h" -#include "TextureConversionShader.h" -#include "DX9_PixelShaderCache.h" -#include "VertexShaderManager.h" -#include "DX9_VertexShaderCache.h" -#include "DX9_FramebufferManager.h" -#include "VideoConfig.h" -#include "ImageWrite.h" -#include "DX9_Render.h" -#include "DX9_TextureCache.h" -#include "Math.h" -#include "FileUtil.h" - -#include "../Main.h" - -namespace DX9 -{ - -namespace TextureConverter -{ - -struct TransformBuffer -{ - LPDIRECT3DTEXTURE9 FBTexture; - LPDIRECT3DSURFACE9 RenderSurface; - LPDIRECT3DSURFACE9 ReadSurface; - int Width; - int Height; -}; -const u32 NUM_TRANSFORM_BUFFERS = 16; -static TransformBuffer TrnBuffers[NUM_TRANSFORM_BUFFERS]; -static u32 WorkingBuffers = 0; - -static LPDIRECT3DPIXELSHADER9 s_rgbToYuyvProgram = NULL; -static LPDIRECT3DPIXELSHADER9 s_yuyvToRgbProgram = NULL; - -// Not all slots are taken - but who cares. -const u32 NUM_ENCODING_PROGRAMS = 64; -static LPDIRECT3DPIXELSHADER9 s_encodingPrograms[NUM_ENCODING_PROGRAMS]; - -void CreateRgbToYuyvProgram() -{ - // Output is BGRA because that is slightly faster than RGBA. - char* FProgram = new char[2048]; - sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" - "uniform float4 textureDims : register(c%d);\n" - "uniform sampler samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float2 uv1 = float2((uv0.x + 1.0f)/ blkDims.z, uv0.y / blkDims.w);\n" - " float3 c0 = tex2D(samp0, uv0.xy / blkDims.zw).rgb;\n" - " float3 c1 = tex2D(samp0, uv1).rgb;\n" - " float3 y_const = float3(0.257f,0.504f,0.098f);\n" - " float3 u_const = float3(-0.148f,-0.291f,0.439f);\n" - " float3 v_const = float3(0.439f,-0.368f,-0.071f);\n" - " float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n" - " float3 c01 = (c0 + c1) * 0.5f;\n" - " ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" - "}\n",C_COLORMATRIX,C_COLORMATRIX+1); - - s_rgbToYuyvProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); - if (!s_rgbToYuyvProgram) { - ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program"); - } - delete [] FProgram; -} - -void CreateYuyvToRgbProgram() -{ - char* FProgram = new char[2048]; - sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" - "uniform float4 textureDims : register(c%d);\n" - "uniform sampler samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float4 c0 = tex2D(samp0, uv0 / blkDims.zw).rgba;\n" - " float f = step(0.5, frac(uv0.x));\n" - " float y = lerp(c0.b, c0.r, f);\n" - " float yComp = 1.164f * (y - 0.0625f);\n" - " float uComp = c0.g - 0.5f;\n" - " float vComp = c0.a - 0.5f;\n" - - " ocol0 = float4(yComp + (1.596f * vComp),\n" - " yComp - (0.813f * vComp) - (0.391f * uComp),\n" - " yComp + (2.018f * uComp),\n" - " 1.0f);\n" - "}\n",C_COLORMATRIX,C_COLORMATRIX+1); - s_yuyvToRgbProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); - if (!s_yuyvToRgbProgram) { - ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program"); - } - delete [] FProgram; -} - -LPDIRECT3DPIXELSHADER9 GetOrCreateEncodingShader(u32 format) -{ - if (format > NUM_ENCODING_PROGRAMS) - { - PanicAlert("Unknown texture copy format: 0x%x\n", format); - return s_encodingPrograms[0]; - } - - if (!s_encodingPrograms[format]) - { - const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_D3D9); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - - SaveData(szTemp, shader); - } -#endif - s_encodingPrograms[format] = D3D::CompileAndCreatePixelShader(shader, (int)strlen(shader)); - if (!s_encodingPrograms[format]) { - ERROR_LOG(VIDEO, "Failed to create encoding fragment program"); - } - } - return s_encodingPrograms[format]; -} - -void Init() -{ - for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) - { - s_encodingPrograms[i] = NULL; - } - for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++) - { - TrnBuffers[i].FBTexture = NULL; - TrnBuffers[i].RenderSurface = NULL; - TrnBuffers[i].ReadSurface = NULL; - TrnBuffers[i].Width = 0; - TrnBuffers[i].Height = 0; - } - CreateRgbToYuyvProgram(); - CreateYuyvToRgbProgram(); - -} - -void Shutdown() -{ - if(s_rgbToYuyvProgram) - s_rgbToYuyvProgram->Release(); - s_rgbToYuyvProgram = NULL; - if(s_yuyvToRgbProgram) - s_yuyvToRgbProgram->Release(); - s_yuyvToRgbProgram=NULL; - - for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) - { - if(s_encodingPrograms[i]) - s_encodingPrograms[i]->Release(); - s_encodingPrograms[i] = NULL; - } - for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++) - { - if(TrnBuffers[i].RenderSurface != NULL) - TrnBuffers[i].RenderSurface->Release(); - TrnBuffers[i].RenderSurface = NULL; - - if(TrnBuffers[i].ReadSurface != NULL) - TrnBuffers[i].ReadSurface->Release(); - TrnBuffers[i].ReadSurface = NULL; - - if(TrnBuffers[i].FBTexture != NULL) - TrnBuffers[i].FBTexture->Release(); - TrnBuffers[i].FBTexture = NULL; - - TrnBuffers[i].Width = 0; - TrnBuffers[i].Height = 0; - } - WorkingBuffers = 0; -} - -void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter) -{ - HRESULT hr; - u32 index =0; - while(index < WorkingBuffers && (TrnBuffers[index].Width != dstWidth || TrnBuffers[index].Height != dstHeight)) - index++; - - LPDIRECT3DSURFACE9 s_texConvReadSurface = NULL; - LPDIRECT3DSURFACE9 Rendersurf = NULL; - - if (index >= WorkingBuffers) - { - if (WorkingBuffers < NUM_TRANSFORM_BUFFERS) - WorkingBuffers++; - if (index >= WorkingBuffers) - index--; - if (TrnBuffers[index].RenderSurface != NULL) - { - TrnBuffers[index].RenderSurface->Release(); - TrnBuffers[index].RenderSurface = NULL; - } - if (TrnBuffers[index].ReadSurface != NULL) - { - TrnBuffers[index].ReadSurface->Release(); - TrnBuffers[index].ReadSurface = NULL; - } - if (TrnBuffers[index].FBTexture != NULL) - { - TrnBuffers[index].FBTexture->Release(); - TrnBuffers[index].FBTexture = NULL; - } - TrnBuffers[index].Width = dstWidth; - TrnBuffers[index].Height = dstHeight; - D3D::dev->CreateTexture(dstWidth, dstHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, &TrnBuffers[index].FBTexture, NULL); - TrnBuffers[index].FBTexture->GetSurfaceLevel(0,&TrnBuffers[index].RenderSurface); - D3D::dev->CreateOffscreenPlainSurface(dstWidth, dstHeight, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &TrnBuffers[index].ReadSurface, NULL ); - } - - s_texConvReadSurface = TrnBuffers[index].ReadSurface; - Rendersurf = TrnBuffers[index].RenderSurface; - - hr = D3D::dev->SetDepthStencilSurface(NULL); - hr = D3D::dev->SetRenderTarget(0, Rendersurf); - - if (linearFilter) - { - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - } - else - { - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - } - - D3DVIEWPORT9 vp; - vp.X = 0; - vp.Y = 0; - vp.Width = dstWidth; - vp.Height = dstHeight; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - hr = D3D::dev->SetViewport(&vp); - RECT SrcRect; - SrcRect.top = sourceRc.top; - SrcRect.left = sourceRc.left; - SrcRect.right = sourceRc.right; - SrcRect.bottom = sourceRc.bottom; - RECT DstRect; - DstRect.top = 0; - DstRect.left = 0; - DstRect.right = dstWidth; - DstRect.bottom = dstHeight; - - - // Draw... - D3D::drawShadedTexQuad(srcTexture,&SrcRect,1,1,dstWidth,dstHeight,shader,VertexShaderCache::GetSimpleVertexShader(0)); - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - // .. and then readback the results. - // TODO: make this less slow. - - D3DLOCKED_RECT drect; - - - hr = D3D::dev->GetRenderTargetData(Rendersurf,s_texConvReadSurface); - if((hr = s_texConvReadSurface->LockRect(&drect, &DstRect, D3DLOCK_READONLY)) != D3D_OK) - { - PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : - hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); - - } - else - { - int writeStride = bpmem.copyMipMapStrideChannels * 32; - - if (writeStride != readStride && toTexture) - { - // writing to a texture of a different size - - int readHeight = readStride / dstWidth; - - int readStart = 0; - int readLoops = dstHeight / (readHeight/4); // 4 bytes per pixel - u8 *Source = (u8*)drect.pBits; - for (int i = 0; i < readLoops; i++) - { - int readDist = dstWidth*readHeight; - memcpy(destAddr,Source,readDist); - Source += readDist; - destAddr += writeStride; - } - } - else - memcpy(destAddr,drect.pBits,dstWidth*dstHeight*4);// 4 bytes per pixel - - hr = s_texConvReadSurface->UnlockRect(); - } -} - -void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) -{ - u32 format = copyfmt; - - if (bFromZBuffer) - { - format |= _GX_TF_ZTF; - if (copyfmt == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) - format |= _GX_TF_CTF; - - LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format); - if (!texconv_shader) - return; - - u8 *dest_ptr = Memory_GetPtr(address); - - LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? - FramebufferManager::GetEFBDepthTexture(source) : - FramebufferManager::GetEFBColorTexture(source); - int width = (source.right - source.left) >> bScaleByHalf; - int height = (source.bottom - source.top) >> bScaleByHalf; - - int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); - - // Invalidate any existing texture covering this memory range. - // TODO - don't delete the texture if it already exists, just replace the contents. - TextureCache::InvalidateRange(address, size_in_bytes); - - u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; - u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; - u16 samples = TextureConversionShader::GetEncodedSampleCount(format); - - // only copy on cache line boundaries - // extra pixels are copied but not displayed in the resulting texture - s32 expandedWidth = (width + blkW) & (~blkW); - s32 expandedHeight = (height + blkH) & (~blkH); - - float MValueX = Renderer::GetTargetScaleX(); - float MValueY = Renderer::GetTargetScaleY(); - - float Xstride = (float)((Renderer::GetFullTargetWidth() - Renderer::GetTargetWidth()) / 2); - float Ystride = (float)((Renderer::GetFullTargetHeight() - Renderer::GetTargetHeight()) / 2); - - float sampleStride = bScaleByHalf?2.0f:1.0f; - - TextureConversionShader::SetShaderParameters( - (float)expandedWidth, - expandedHeight * MValueY, - source.left * MValueX + Xstride , - source.top * MValueY + Ystride, - sampleStride * MValueX, - sampleStride * MValueY, - (float)Renderer::GetFullTargetWidth(), - (float)Renderer::GetFullTargetHeight()); - - TargetRectangle scaledSource; - scaledSource.top = 0; - scaledSource.bottom = expandedHeight; - scaledSource.left = 0; - scaledSource.right = expandedWidth / samples; - int cacheBytes = 32; - if ((format & 0x0f) == 6) - cacheBytes = 64; - - int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); - g_renderer->ResetAPIState(); - EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - g_renderer->RestoreAPIState(); -} - -u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) -{ - u32 format = copyfmt; - - if (bFromZBuffer) - { - format |= _GX_TF_ZTF; - if (copyfmt == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) - format |= _GX_TF_CTF; - - LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format); - if (!texconv_shader) - return 0; - - u8 *dest_ptr = Memory_GetPtr(address); - - int width = (source.right - source.left) >> bScaleByHalf; - int height = (source.bottom - source.top) >> bScaleByHalf; - - int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); - - u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; - u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; - u16 samples = TextureConversionShader::GetEncodedSampleCount(format); - - // only copy on cache line boundaries - // extra pixels are copied but not displayed in the resulting texture - s32 expandedWidth = (width + blkW) & (~blkW); - s32 expandedHeight = (height + blkH) & (~blkH); - - float sampleStride = bScaleByHalf?2.0f:1.0f; - - TextureConversionShader::SetShaderParameters( - (float)expandedWidth, - expandedHeight * MValueY, - source.left * MValueX + Xstride , - source.top * MValueY + Ystride, - sampleStride * MValueX, - sampleStride * MValueY, - (float)SourceW, - (float)SourceH); - - TargetRectangle scaledSource; - scaledSource.top = 0; - scaledSource.bottom = expandedHeight; - scaledSource.left = 0; - scaledSource.right = expandedWidth / samples; - int cacheBytes = 32; - if ((format & 0x0f) == 6) - cacheBytes = 64; - - int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); - EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); - TextureCache::MakeRangeDynamic(address,size_in_bytes); - u64 Hashvalue = 0; - Hashvalue = GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples); - return Hashvalue; -} - - -void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,u8* destAddr, int dstWidth, int dstHeight) -{ - TextureConversionShader::SetShaderParameters( - (float)dstWidth, - (float)dstHeight, - 0.0f , - 0.0f, - 1.0f, - 1.0f, - (float)Renderer::GetFullTargetWidth(), - (float)Renderer::GetFullTargetHeight()); - g_renderer->ResetAPIState(); - EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - g_renderer->RestoreAPIState(); -} - - -// Should be scale free. -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture) -{ - u8* srcAddr = Memory_GetPtr(xfbAddr); - if (!srcAddr) - { - WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); - return; - } - - int srcFmtWidth = srcWidth / 2; - - g_renderer->ResetAPIState(); // reset any game specific settings - LPDIRECT3DTEXTURE9 s_srcTexture = D3D::CreateTexture2D(srcAddr, srcFmtWidth, srcHeight, srcFmtWidth, D3DFMT_A8R8G8B8, false); - LPDIRECT3DSURFACE9 Rendersurf = NULL; - destTexture->GetSurfaceLevel(0,&Rendersurf); - D3D::dev->SetDepthStencilSurface(NULL); - D3D::dev->SetRenderTarget(0, Rendersurf); - - D3DVIEWPORT9 vp; - - // Stretch picture with increased internal resolution - vp.X = 0; - vp.Y = 0; - vp.Width = srcWidth; - vp.Height = srcHeight; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - RECT destrect; - destrect.bottom = srcHeight; - destrect.left = 0; - destrect.right = srcWidth; - destrect.top = 0; - - RECT sourcerect; - sourcerect.bottom = srcHeight; - sourcerect.left = 0; - sourcerect.right = srcFmtWidth; - sourcerect.top = 0; - - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - - TextureConversionShader::SetShaderParameters( - (float)srcFmtWidth, - (float)srcHeight, - 0.0f , - 0.0f, - 1.0f, - 1.0f, - (float)srcFmtWidth, - (float)srcHeight); - D3D::drawShadedTexQuad( - s_srcTexture, - &sourcerect, - 1 , - 1, - srcWidth, - srcHeight, - s_yuyvToRgbProgram, - VertexShaderCache::GetSimpleVertexShader(0)); - - - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); - D3D::SetTexture(0,NULL); - D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - g_renderer->RestoreAPIState(); - Rendersurf->Release(); - s_srcTexture->Release(); -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Fast image conversion using OpenGL shaders. +// This kind of stuff would be a LOT nicer with OpenCL. + +#include "DX9_TextureConverter.h" +#include "TextureConversionShader.h" +#include "DX9_PixelShaderCache.h" +#include "VertexShaderManager.h" +#include "DX9_VertexShaderCache.h" +#include "DX9_FramebufferManager.h" +#include "VideoConfig.h" +#include "ImageWrite.h" +#include "DX9_Render.h" +#include "DX9_TextureCache.h" +#include "Math.h" +#include "FileUtil.h" + +#include "../Main.h" + +namespace DX9 +{ + +namespace TextureConverter +{ + +struct TransformBuffer +{ + LPDIRECT3DTEXTURE9 FBTexture; + LPDIRECT3DSURFACE9 RenderSurface; + LPDIRECT3DSURFACE9 ReadSurface; + int Width; + int Height; +}; +const u32 NUM_TRANSFORM_BUFFERS = 16; +static TransformBuffer TrnBuffers[NUM_TRANSFORM_BUFFERS]; +static u32 WorkingBuffers = 0; + +static LPDIRECT3DPIXELSHADER9 s_rgbToYuyvProgram = NULL; +static LPDIRECT3DPIXELSHADER9 s_yuyvToRgbProgram = NULL; + +// Not all slots are taken - but who cares. +const u32 NUM_ENCODING_PROGRAMS = 64; +static LPDIRECT3DPIXELSHADER9 s_encodingPrograms[NUM_ENCODING_PROGRAMS]; + +void CreateRgbToYuyvProgram() +{ + // Output is BGRA because that is slightly faster than RGBA. + char* FProgram = new char[2048]; + sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" + "uniform float4 textureDims : register(c%d);\n" + "uniform sampler samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float2 uv1 = float2((uv0.x + 1.0f)/ blkDims.z, uv0.y / blkDims.w);\n" + " float3 c0 = tex2D(samp0, uv0.xy / blkDims.zw).rgb;\n" + " float3 c1 = tex2D(samp0, uv1).rgb;\n" + " float3 y_const = float3(0.257f,0.504f,0.098f);\n" + " float3 u_const = float3(-0.148f,-0.291f,0.439f);\n" + " float3 v_const = float3(0.439f,-0.368f,-0.071f);\n" + " float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n" + " float3 c01 = (c0 + c1) * 0.5f;\n" + " ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" + "}\n",C_COLORMATRIX,C_COLORMATRIX+1); + + s_rgbToYuyvProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); + if (!s_rgbToYuyvProgram) { + ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program"); + } + delete [] FProgram; +} + +void CreateYuyvToRgbProgram() +{ + char* FProgram = new char[2048]; + sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" + "uniform float4 textureDims : register(c%d);\n" + "uniform sampler samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float4 c0 = tex2D(samp0, uv0 / blkDims.zw).rgba;\n" + " float f = step(0.5, frac(uv0.x));\n" + " float y = lerp(c0.b, c0.r, f);\n" + " float yComp = 1.164f * (y - 0.0625f);\n" + " float uComp = c0.g - 0.5f;\n" + " float vComp = c0.a - 0.5f;\n" + + " ocol0 = float4(yComp + (1.596f * vComp),\n" + " yComp - (0.813f * vComp) - (0.391f * uComp),\n" + " yComp + (2.018f * uComp),\n" + " 1.0f);\n" + "}\n",C_COLORMATRIX,C_COLORMATRIX+1); + s_yuyvToRgbProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); + if (!s_yuyvToRgbProgram) { + ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program"); + } + delete [] FProgram; +} + +LPDIRECT3DPIXELSHADER9 GetOrCreateEncodingShader(u32 format) +{ + if (format > NUM_ENCODING_PROGRAMS) + { + PanicAlert("Unknown texture copy format: 0x%x\n", format); + return s_encodingPrograms[0]; + } + + if (!s_encodingPrograms[format]) + { + const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_D3D9); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + + SaveData(szTemp, shader); + } +#endif + s_encodingPrograms[format] = D3D::CompileAndCreatePixelShader(shader, (int)strlen(shader)); + if (!s_encodingPrograms[format]) { + ERROR_LOG(VIDEO, "Failed to create encoding fragment program"); + } + } + return s_encodingPrograms[format]; +} + +void Init() +{ + for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) + { + s_encodingPrograms[i] = NULL; + } + for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++) + { + TrnBuffers[i].FBTexture = NULL; + TrnBuffers[i].RenderSurface = NULL; + TrnBuffers[i].ReadSurface = NULL; + TrnBuffers[i].Width = 0; + TrnBuffers[i].Height = 0; + } + CreateRgbToYuyvProgram(); + CreateYuyvToRgbProgram(); + +} + +void Shutdown() +{ + if(s_rgbToYuyvProgram) + s_rgbToYuyvProgram->Release(); + s_rgbToYuyvProgram = NULL; + if(s_yuyvToRgbProgram) + s_yuyvToRgbProgram->Release(); + s_yuyvToRgbProgram=NULL; + + for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) + { + if(s_encodingPrograms[i]) + s_encodingPrograms[i]->Release(); + s_encodingPrograms[i] = NULL; + } + for (unsigned int i = 0; i < NUM_TRANSFORM_BUFFERS; i++) + { + if(TrnBuffers[i].RenderSurface != NULL) + TrnBuffers[i].RenderSurface->Release(); + TrnBuffers[i].RenderSurface = NULL; + + if(TrnBuffers[i].ReadSurface != NULL) + TrnBuffers[i].ReadSurface->Release(); + TrnBuffers[i].ReadSurface = NULL; + + if(TrnBuffers[i].FBTexture != NULL) + TrnBuffers[i].FBTexture->Release(); + TrnBuffers[i].FBTexture = NULL; + + TrnBuffers[i].Width = 0; + TrnBuffers[i].Height = 0; + } + WorkingBuffers = 0; +} + +void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter) +{ + HRESULT hr; + u32 index =0; + while(index < WorkingBuffers && (TrnBuffers[index].Width != dstWidth || TrnBuffers[index].Height != dstHeight)) + index++; + + LPDIRECT3DSURFACE9 s_texConvReadSurface = NULL; + LPDIRECT3DSURFACE9 Rendersurf = NULL; + + if (index >= WorkingBuffers) + { + if (WorkingBuffers < NUM_TRANSFORM_BUFFERS) + WorkingBuffers++; + if (index >= WorkingBuffers) + index--; + if (TrnBuffers[index].RenderSurface != NULL) + { + TrnBuffers[index].RenderSurface->Release(); + TrnBuffers[index].RenderSurface = NULL; + } + if (TrnBuffers[index].ReadSurface != NULL) + { + TrnBuffers[index].ReadSurface->Release(); + TrnBuffers[index].ReadSurface = NULL; + } + if (TrnBuffers[index].FBTexture != NULL) + { + TrnBuffers[index].FBTexture->Release(); + TrnBuffers[index].FBTexture = NULL; + } + TrnBuffers[index].Width = dstWidth; + TrnBuffers[index].Height = dstHeight; + D3D::dev->CreateTexture(dstWidth, dstHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, &TrnBuffers[index].FBTexture, NULL); + TrnBuffers[index].FBTexture->GetSurfaceLevel(0,&TrnBuffers[index].RenderSurface); + D3D::dev->CreateOffscreenPlainSurface(dstWidth, dstHeight, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &TrnBuffers[index].ReadSurface, NULL ); + } + + s_texConvReadSurface = TrnBuffers[index].ReadSurface; + Rendersurf = TrnBuffers[index].RenderSurface; + + hr = D3D::dev->SetDepthStencilSurface(NULL); + hr = D3D::dev->SetRenderTarget(0, Rendersurf); + + if (linearFilter) + { + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + } + else + { + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } + + D3DVIEWPORT9 vp; + vp.X = 0; + vp.Y = 0; + vp.Width = dstWidth; + vp.Height = dstHeight; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + hr = D3D::dev->SetViewport(&vp); + RECT SrcRect; + SrcRect.top = sourceRc.top; + SrcRect.left = sourceRc.left; + SrcRect.right = sourceRc.right; + SrcRect.bottom = sourceRc.bottom; + RECT DstRect; + DstRect.top = 0; + DstRect.left = 0; + DstRect.right = dstWidth; + DstRect.bottom = dstHeight; + + + // Draw... + D3D::drawShadedTexQuad(srcTexture,&SrcRect,1,1,dstWidth,dstHeight,shader,VertexShaderCache::GetSimpleVertexShader(0)); + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + // .. and then readback the results. + // TODO: make this less slow. + + D3DLOCKED_RECT drect; + + + hr = D3D::dev->GetRenderTargetData(Rendersurf,s_texConvReadSurface); + if((hr = s_texConvReadSurface->LockRect(&drect, &DstRect, D3DLOCK_READONLY)) != D3D_OK) + { + PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : + hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); + + } + else + { + int writeStride = bpmem.copyMipMapStrideChannels * 32; + + if (writeStride != readStride && toTexture) + { + // writing to a texture of a different size + + int readHeight = readStride / dstWidth; + + int readStart = 0; + int readLoops = dstHeight / (readHeight/4); // 4 bytes per pixel + u8 *Source = (u8*)drect.pBits; + for (int i = 0; i < readLoops; i++) + { + int readDist = dstWidth*readHeight; + memcpy(destAddr,Source,readDist); + Source += readDist; + destAddr += writeStride; + } + } + else + memcpy(destAddr,drect.pBits,dstWidth*dstHeight*4);// 4 bytes per pixel + + hr = s_texConvReadSurface->UnlockRect(); + } +} + +void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) +{ + u32 format = copyfmt; + + if (bFromZBuffer) + { + format |= _GX_TF_ZTF; + if (copyfmt == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) + format |= _GX_TF_CTF; + + LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format); + if (!texconv_shader) + return; + + u8 *dest_ptr = Memory_GetPtr(address); + + LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? + FramebufferManager::GetEFBDepthTexture(source) : + FramebufferManager::GetEFBColorTexture(source); + int width = (source.right - source.left) >> bScaleByHalf; + int height = (source.bottom - source.top) >> bScaleByHalf; + + int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); + + // Invalidate any existing texture covering this memory range. + // TODO - don't delete the texture if it already exists, just replace the contents. + TextureCache::InvalidateRange(address, size_in_bytes); + + u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; + u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; + u16 samples = TextureConversionShader::GetEncodedSampleCount(format); + + // only copy on cache line boundaries + // extra pixels are copied but not displayed in the resulting texture + s32 expandedWidth = (width + blkW) & (~blkW); + s32 expandedHeight = (height + blkH) & (~blkH); + + float MValueX = Renderer::GetTargetScaleX(); + float MValueY = Renderer::GetTargetScaleY(); + + float Xstride = (float)((Renderer::GetFullTargetWidth() - Renderer::GetTargetWidth()) / 2); + float Ystride = (float)((Renderer::GetFullTargetHeight() - Renderer::GetTargetHeight()) / 2); + + float sampleStride = bScaleByHalf?2.0f:1.0f; + + TextureConversionShader::SetShaderParameters( + (float)expandedWidth, + expandedHeight * MValueY, + source.left * MValueX + Xstride , + source.top * MValueY + Ystride, + sampleStride * MValueX, + sampleStride * MValueY, + (float)Renderer::GetFullTargetWidth(), + (float)Renderer::GetFullTargetHeight()); + + TargetRectangle scaledSource; + scaledSource.top = 0; + scaledSource.bottom = expandedHeight; + scaledSource.left = 0; + scaledSource.right = expandedWidth / samples; + int cacheBytes = 32; + if ((format & 0x0f) == 6) + cacheBytes = 64; + + int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); + g_renderer->ResetAPIState(); + EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + g_renderer->RestoreAPIState(); +} + +u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) +{ + u32 format = copyfmt; + + if (bFromZBuffer) + { + format |= _GX_TF_ZTF; + if (copyfmt == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) + format |= _GX_TF_CTF; + + LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format); + if (!texconv_shader) + return 0; + + u8 *dest_ptr = Memory_GetPtr(address); + + int width = (source.right - source.left) >> bScaleByHalf; + int height = (source.bottom - source.top) >> bScaleByHalf; + + int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); + + u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; + u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; + u16 samples = TextureConversionShader::GetEncodedSampleCount(format); + + // only copy on cache line boundaries + // extra pixels are copied but not displayed in the resulting texture + s32 expandedWidth = (width + blkW) & (~blkW); + s32 expandedHeight = (height + blkH) & (~blkH); + + float sampleStride = bScaleByHalf?2.0f:1.0f; + + TextureConversionShader::SetShaderParameters( + (float)expandedWidth, + expandedHeight * MValueY, + source.left * MValueX + Xstride , + source.top * MValueY + Ystride, + sampleStride * MValueX, + sampleStride * MValueY, + (float)SourceW, + (float)SourceH); + + TargetRectangle scaledSource; + scaledSource.top = 0; + scaledSource.bottom = expandedHeight; + scaledSource.left = 0; + scaledSource.right = expandedWidth / samples; + int cacheBytes = 32; + if ((format & 0x0f) == 6) + cacheBytes = 64; + + int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); + EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); + TextureCache::MakeRangeDynamic(address,size_in_bytes); + u64 Hashvalue = 0; + Hashvalue = GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples); + return Hashvalue; +} + + +void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,u8* destAddr, int dstWidth, int dstHeight) +{ + TextureConversionShader::SetShaderParameters( + (float)dstWidth, + (float)dstHeight, + 0.0f , + 0.0f, + 1.0f, + 1.0f, + (float)Renderer::GetFullTargetWidth(), + (float)Renderer::GetFullTargetHeight()); + g_renderer->ResetAPIState(); + EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + g_renderer->RestoreAPIState(); +} + + +// Should be scale free. +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture) +{ + u8* srcAddr = Memory_GetPtr(xfbAddr); + if (!srcAddr) + { + WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); + return; + } + + int srcFmtWidth = srcWidth / 2; + + g_renderer->ResetAPIState(); // reset any game specific settings + LPDIRECT3DTEXTURE9 s_srcTexture = D3D::CreateTexture2D(srcAddr, srcFmtWidth, srcHeight, srcFmtWidth, D3DFMT_A8R8G8B8, false); + LPDIRECT3DSURFACE9 Rendersurf = NULL; + destTexture->GetSurfaceLevel(0,&Rendersurf); + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, Rendersurf); + + D3DVIEWPORT9 vp; + + // Stretch picture with increased internal resolution + vp.X = 0; + vp.Y = 0; + vp.Width = srcWidth; + vp.Height = srcHeight; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + RECT destrect; + destrect.bottom = srcHeight; + destrect.left = 0; + destrect.right = srcWidth; + destrect.top = 0; + + RECT sourcerect; + sourcerect.bottom = srcHeight; + sourcerect.left = 0; + sourcerect.right = srcFmtWidth; + sourcerect.top = 0; + + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + + TextureConversionShader::SetShaderParameters( + (float)srcFmtWidth, + (float)srcHeight, + 0.0f , + 0.0f, + 1.0f, + 1.0f, + (float)srcFmtWidth, + (float)srcHeight); + D3D::drawShadedTexQuad( + s_srcTexture, + &sourcerect, + 1 , + 1, + srcWidth, + srcHeight, + s_yuyvToRgbProgram, + VertexShaderCache::GetSimpleVertexShader(0)); + + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + D3D::SetTexture(0,NULL); + D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); + g_renderer->RestoreAPIState(); + Rendersurf->Release(); + s_srcTexture->Release(); +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.h index bff2e88fd3..e04757acfe 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_TextureConverter.h @@ -1,53 +1,53 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _TEXTURECONVERTER_H_ -#define _TEXTURECONVERTER_H_ - -#include "VideoCommon.h" -#include "DX9_D3DBase.h" -#include "DX9_D3DTexture.h" -#include "DX9_D3DUtil.h" -#include "DX9_D3DShader.h" - -namespace DX9 -{ - -// Converts textures between formats -// TODO: support multiple texture formats -namespace TextureConverter -{ - -void Init(); -void Shutdown(); - -void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, - u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); - -void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight); - -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture); - -u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); - - -} - -} - -#endif // _TEXTURECONVERTER_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _TEXTURECONVERTER_H_ +#define _TEXTURECONVERTER_H_ + +#include "VideoCommon.h" +#include "DX9_D3DBase.h" +#include "DX9_D3DTexture.h" +#include "DX9_D3DUtil.h" +#include "DX9_D3DShader.h" + +namespace DX9 +{ + +// Converts textures between formats +// TODO: support multiple texture formats +namespace TextureConverter +{ + +void Init(); +void Shutdown(); + +void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, + u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); + +void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight); + +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture); + +u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); + + +} + +} + +#endif // _TEXTURECONVERTER_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.cpp index 0669667350..640274e96d 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.cpp @@ -1,135 +1,135 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "Common.h" -#include "FileUtil.h" - -#include "DX9_D3DBase.h" -#include "Fifo.h" -#include "Statistics.h" -#include "Profiler.h" -#include "DX9_VertexManager.h" -#include "OpcodeDecoding.h" -#include "IndexGenerator.h" -#include "VertexShaderManager.h" -#include "DX9_VertexShaderCache.h" -#include "PixelShaderManager.h" -#include "DX9_PixelShaderCache.h" -#include "NativeVertexFormat.h" -#include "NativeVertexWriter.h" -#include "DX9_TextureCache.h" - -#include "../Main.h" - -#include "BPStructs.h" -#include "XFStructs.h" - -//#include "debugger/debugger.h" - -namespace DX9 -{ - -using namespace D3D; - -// internal state for loading vertices -extern NativeVertexFormat *g_nativeVertexFmt; - -inline void DumpBadShaders() -{ -#if defined(_DEBUG) || defined(DEBUGFAST) - std::string error_shaders; - error_shaders.append(VertexShaderCache::GetCurrentShaderCode()); - error_shaders.append(PixelShaderCache::GetCurrentShaderCode()); - char filename[512] = "bad_shader_combo_0.txt"; - int which = 0; - while (File::Exists(filename)) - { - which++; - sprintf(filename, "bad_shader_combo_%i.txt", which); - } - File::WriteStringToFile(true, error_shaders, filename); - PanicAlert("DrawIndexedPrimitiveUP failed. Shaders written to %s", filename); -#endif -} - -void VertexManager::Draw(u32 stride, bool alphapass) -{ - if (alphapass) - { - DWORD write = 0; - if (false == g_pixel_shader_cache->SetShader(true)) - { - //DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");}); - //goto shader_fail; - return; - } - // update alpha only - D3D::ChangeRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); - D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false); - } - - if (IndexGenerator::GetNumTriangles() > 0) - { - if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( - D3DPT_TRIANGLELIST, - 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumTriangles(), - TIBuffer, - D3DFMT_INDEX16, - LocalVBuffer, - stride))) - { - DumpBadShaders(); - } - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumLines() > 0) - { - if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( - D3DPT_LINELIST, - 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumLines(), - LIBuffer, - D3DFMT_INDEX16, - LocalVBuffer, - stride))) - { - DumpBadShaders(); - } - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumPoints() > 0) - { - if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( - D3DPT_POINTLIST, - 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumPoints(), - PIBuffer, - D3DFMT_INDEX16, - LocalVBuffer, - stride))) - { - DumpBadShaders(); - } - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - - if (alphapass) - { - D3D::RefreshRenderState(D3DRS_COLORWRITEENABLE); - D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE); - } -} - -} // namespace +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "FileUtil.h" + +#include "DX9_D3DBase.h" +#include "Fifo.h" +#include "Statistics.h" +#include "Profiler.h" +#include "DX9_VertexManager.h" +#include "OpcodeDecoding.h" +#include "IndexGenerator.h" +#include "VertexShaderManager.h" +#include "DX9_VertexShaderCache.h" +#include "PixelShaderManager.h" +#include "DX9_PixelShaderCache.h" +#include "NativeVertexFormat.h" +#include "NativeVertexWriter.h" +#include "DX9_TextureCache.h" + +#include "../Main.h" + +#include "BPStructs.h" +#include "XFStructs.h" + +//#include "debugger/debugger.h" + +namespace DX9 +{ + +using namespace D3D; + +// internal state for loading vertices +extern NativeVertexFormat *g_nativeVertexFmt; + +inline void DumpBadShaders() +{ +#if defined(_DEBUG) || defined(DEBUGFAST) + std::string error_shaders; + error_shaders.append(VertexShaderCache::GetCurrentShaderCode()); + error_shaders.append(PixelShaderCache::GetCurrentShaderCode()); + char filename[512] = "bad_shader_combo_0.txt"; + int which = 0; + while (File::Exists(filename)) + { + which++; + sprintf(filename, "bad_shader_combo_%i.txt", which); + } + File::WriteStringToFile(true, error_shaders, filename); + PanicAlert("DrawIndexedPrimitiveUP failed. Shaders written to %s", filename); +#endif +} + +void VertexManager::Draw(u32 stride, bool alphapass) +{ + if (alphapass) + { + DWORD write = 0; + if (false == g_pixel_shader_cache->SetShader(true)) + { + //DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");}); + //goto shader_fail; + return; + } + // update alpha only + D3D::ChangeRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA); + D3D::ChangeRenderState(D3DRS_ALPHABLENDENABLE, false); + } + + if (IndexGenerator::GetNumTriangles() > 0) + { + if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( + D3DPT_TRIANGLELIST, + 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumTriangles(), + TIBuffer, + D3DFMT_INDEX16, + LocalVBuffer, + stride))) + { + DumpBadShaders(); + } + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumLines() > 0) + { + if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( + D3DPT_LINELIST, + 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumLines(), + LIBuffer, + D3DFMT_INDEX16, + LocalVBuffer, + stride))) + { + DumpBadShaders(); + } + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumPoints() > 0) + { + if (FAILED(D3D::dev->DrawIndexedPrimitiveUP( + D3DPT_POINTLIST, + 0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumPoints(), + PIBuffer, + D3DFMT_INDEX16, + LocalVBuffer, + stride))) + { + DumpBadShaders(); + } + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + + if (alphapass) + { + D3D::RefreshRenderState(D3DRS_COLORWRITEENABLE); + D3D::RefreshRenderState(D3DRS_ALPHABLENDENABLE); + } +} + +} // namespace diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.h index e0c296f7c9..37ff652e2d 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexManager.h @@ -1,39 +1,39 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _VERTEXMANAGER_H -#define _VERTEXMANAGER_H - -#include "CPMemory.h" -#include "VertexLoader.h" - -#include "../VertexManager.h" - -namespace DX9 -{ - -class VertexManager : public ::VertexManagerBase -{ -public: - void Draw(u32 stride, bool alphapass); - - NativeVertexFormat* CreateNativeVertexFormat(); -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _VERTEXMANAGER_H +#define _VERTEXMANAGER_H + +#include "CPMemory.h" +#include "VertexLoader.h" + +#include "../VertexManager.h" + +namespace DX9 +{ + +class VertexManager : public ::VertexManagerBase +{ +public: + void Draw(u32 stride, bool alphapass); + + NativeVertexFormat* CreateNativeVertexFormat(); +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.cpp index 86261d9b9c..ed36e85fee 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.cpp @@ -1,302 +1,302 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "Common.h" -#include "FileUtil.h" -#include "LinearDiskCache.h" - -#include "DX9_D3DBase.h" -#include "DX9_D3DShader.h" -#include "Statistics.h" -#include "Profiler.h" -#include "VideoConfig.h" -#include "DX9_VertexShaderCache.h" -#include "VertexLoader.h" -#include "BPMemory.h" -#include "XFMemory.h" - -//#include "debugger/debugger.h" - -#include "../Main.h" - -namespace DX9 -{ - -VertexShaderCache::VSCache VertexShaderCache::vshaders; -const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry; - -#define MAX_SSAA_SHADERS 3 - -static LPDIRECT3DVERTEXSHADER9 SimpleVertexShader[MAX_SSAA_SHADERS]; -static LPDIRECT3DVERTEXSHADER9 ClearVertexShader; - -LinearDiskCache g_vs_disk_cache; - -LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetSimpleVertexShader(int level) -{ - return SimpleVertexShader[level % MAX_SSAA_SHADERS]; -} - -LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetClearVertexShader() -{ - return ClearVertexShader; -} - - -void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - const float f[4] = { f1, f2, f3, f4 }; - D3D::dev->SetVertexShaderConstantF(const_number, f, 1); -} - -void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f) -{ - D3D::dev->SetVertexShaderConstantF(const_number, f, 1); -} - -void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f) -{ - float buf[4*C_VENVCONST_END]; - for (unsigned int i = 0; i < count; i++) - { - buf[4*i ] = *f++; - buf[4*i+1] = *f++; - buf[4*i+2] = *f++; - buf[4*i+3] = 0.f; - } - D3D::dev->SetVertexShaderConstantF(const_number, buf, count); -} - -void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f) -{ - D3D::dev->SetVertexShaderConstantF(const_number, f, count); -} - -class VertexShaderCacheInserter : public LinearDiskCacheReader { -public: - void Read(const u8 *key, int key_size, const u8 *value, int value_size) - { - VERTEXSHADERUID uid; - if (key_size != sizeof(uid)) { - ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache"); - return; - } - memcpy(&uid, key, key_size); - VertexShaderCache::InsertByteCode(uid, value, value_size, false); - } -}; - -VertexShaderCache::VertexShaderCache() -{ - char* vProg = new char[2048]; - sprintf(vProg,"struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float2 vTexCoord : TEXCOORD0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0;\n" - "return OUT;\n" - "}\n"); - - SimpleVertexShader[0] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); - - sprintf(vProg,"struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vColor0 : COLOR0;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" - "{\n" - "VSOUTPUT OUT;\n" - "OUT.vPosition = inPosition;\n" - "OUT.vColor0 = inColor0;\n" - "return OUT;\n" - "}\n"); - - ClearVertexShader = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); - - sprintf(vProg, "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vTexCoord : TEXCOORD0;\n" - "float4 vTexCoord1 : TEXCOORD1;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n" - "{\n" - "VSOUTPUT OUT;" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0.xyyx;\n" - "OUT.vTexCoord1 = inTEX2;\n" - "return OUT;\n" - "}\n"); - SimpleVertexShader[1] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); - - sprintf(vProg, "struct VSOUTPUT\n" - "{\n" - "float4 vPosition : POSITION;\n" - "float4 vTexCoord : TEXCOORD0;\n" - "float4 vTexCoord1 : TEXCOORD1;\n" - "float4 vTexCoord2 : TEXCOORD2;\n" - "float4 vTexCoord3 : TEXCOORD3;\n" - "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n" - "{\n" - "VSOUTPUT OUT;" - "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0.xyyx;\n" - "OUT.vTexCoord1 = inTEX0.xyyx + (float4(-1.0f,-0.5f, 1.0f,-0.5f) * inTEX1.xyyx);\n" - "OUT.vTexCoord2 = inTEX0.xyyx + (float4( 1.0f, 0.5f,-1.0f, 0.5f) * inTEX1.xyyx);\n" - "OUT.vTexCoord3 = inTEX2;\n" - "return OUT;\n" - "}\n"); - SimpleVertexShader[2] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); - - Clear(); - delete [] vProg; - - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - SETSTAT(stats.numVertexShadersCreated, 0); - SETSTAT(stats.numVertexShadersAlive, 0); - - char cache_filename[MAX_PATH]; - sprintf(cache_filename, "%sdx9-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); - VertexShaderCacheInserter inserter; - int read_items = g_vs_disk_cache.OpenAndRead(cache_filename, &inserter); -} - -void VertexShaderCache::Clear() -{ - VSCache::iterator - iter = vshaders.begin(), - vsend = vshaders.end(); - for (; iter != vsend; ++iter) - iter->second.Destroy(); - - vshaders.clear(); - - memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); -} - -VertexShaderCache::~VertexShaderCache() -{ - for (int i = 0; i < MAX_SSAA_SHADERS; i++) - { - if (SimpleVertexShader[i]) - SimpleVertexShader[i]->Release(); - SimpleVertexShader[i] = NULL; - } - - if (ClearVertexShader) - ClearVertexShader->Release(); - - ClearVertexShader = NULL; - - g_vs_disk_cache.Sync(); - g_vs_disk_cache.Close(); -} - -bool VertexShaderCache::SetShader(u32 components) -{ - DVSTARTPROFILE(); - - VERTEXSHADERUID uid; - GetVertexShaderId(&uid, components); - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) - { - if (vshaders[uid].shader) - return true; - else - return false; - } - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); - - VSCache::iterator iter; - iter = vshaders.find(uid); - if (iter != vshaders.end()) - { - iter->second.frameCount = frameCount; - const VSCacheEntry &entry = iter->second; - last_entry = &entry; - - //DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); - if (entry.shader) - { - D3D::SetVertexShader(entry.shader); - return true; - } - else - return false; - } - - const char *code = GenerateVertexShaderCode(components, API_D3D9); - u8 *bytecode; - int bytecodelen; - if (!D3D::CompileVertexShader(code, (int)strlen(code), &bytecode, &bytecodelen)) - { - if (g_ActiveConfig.bShowShaderErrors) - { - PanicAlert("Failed to compile Vertex Shader:\n\n%s", code); - } - return false; - } - g_vs_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen); - g_vs_disk_cache.Sync(); - - bool result = InsertByteCode(uid, bytecode, bytecodelen, true); - delete [] bytecode; - return result; -} - -bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) { - LPDIRECT3DVERTEXSHADER9 shader = D3D::CreateVertexShaderFromByteCode(bytecode, bytecodelen); - - // Make an entry in the table - VSCacheEntry entry; - entry.shader = shader; - entry.frameCount = frameCount; - - vshaders[uid] = entry; - last_entry = &vshaders[uid]; - if (!shader) - return false; - - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); - if (activate) - { - D3D::SetVertexShader(shader); - return true; - } - return false; -} - -#if defined(_DEBUG) || defined(DEBUGFAST) -std::string VertexShaderCache::GetCurrentShaderCode() -{ - return "(N/A)\n"; -} -#endif - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "Common.h" +#include "FileUtil.h" +#include "LinearDiskCache.h" + +#include "DX9_D3DBase.h" +#include "DX9_D3DShader.h" +#include "Statistics.h" +#include "Profiler.h" +#include "VideoConfig.h" +#include "DX9_VertexShaderCache.h" +#include "VertexLoader.h" +#include "BPMemory.h" +#include "XFMemory.h" + +//#include "debugger/debugger.h" + +#include "../Main.h" + +namespace DX9 +{ + +VertexShaderCache::VSCache VertexShaderCache::vshaders; +const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry; + +#define MAX_SSAA_SHADERS 3 + +static LPDIRECT3DVERTEXSHADER9 SimpleVertexShader[MAX_SSAA_SHADERS]; +static LPDIRECT3DVERTEXSHADER9 ClearVertexShader; + +LinearDiskCache g_vs_disk_cache; + +LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetSimpleVertexShader(int level) +{ + return SimpleVertexShader[level % MAX_SSAA_SHADERS]; +} + +LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetClearVertexShader() +{ + return ClearVertexShader; +} + + +void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + const float f[4] = { f1, f2, f3, f4 }; + D3D::dev->SetVertexShaderConstantF(const_number, f, 1); +} + +void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f) +{ + D3D::dev->SetVertexShaderConstantF(const_number, f, 1); +} + +void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f) +{ + float buf[4*C_VENVCONST_END]; + for (unsigned int i = 0; i < count; i++) + { + buf[4*i ] = *f++; + buf[4*i+1] = *f++; + buf[4*i+2] = *f++; + buf[4*i+3] = 0.f; + } + D3D::dev->SetVertexShaderConstantF(const_number, buf, count); +} + +void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f) +{ + D3D::dev->SetVertexShaderConstantF(const_number, f, count); +} + +class VertexShaderCacheInserter : public LinearDiskCacheReader { +public: + void Read(const u8 *key, int key_size, const u8 *value, int value_size) + { + VERTEXSHADERUID uid; + if (key_size != sizeof(uid)) { + ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache"); + return; + } + memcpy(&uid, key, key_size); + VertexShaderCache::InsertByteCode(uid, value, value_size, false); + } +}; + +VertexShaderCache::VertexShaderCache() +{ + char* vProg = new char[2048]; + sprintf(vProg,"struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float2 vTexCoord : TEXCOORD0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0;\n" + "return OUT;\n" + "}\n"); + + SimpleVertexShader[0] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); + + sprintf(vProg,"struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" + "{\n" + "VSOUTPUT OUT;\n" + "OUT.vPosition = inPosition;\n" + "OUT.vColor0 = inColor0;\n" + "return OUT;\n" + "}\n"); + + ClearVertexShader = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); + + sprintf(vProg, "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vTexCoord : TEXCOORD0;\n" + "float4 vTexCoord1 : TEXCOORD1;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n" + "{\n" + "VSOUTPUT OUT;" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0.xyyx;\n" + "OUT.vTexCoord1 = inTEX2;\n" + "return OUT;\n" + "}\n"); + SimpleVertexShader[1] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); + + sprintf(vProg, "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vTexCoord : TEXCOORD0;\n" + "float4 vTexCoord1 : TEXCOORD1;\n" + "float4 vTexCoord2 : TEXCOORD2;\n" + "float4 vTexCoord3 : TEXCOORD3;\n" + "};\n" + "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float4 inTEX2 : TEXCOORD2)\n" + "{\n" + "VSOUTPUT OUT;" + "OUT.vPosition = inPosition;\n" + "OUT.vTexCoord = inTEX0.xyyx;\n" + "OUT.vTexCoord1 = inTEX0.xyyx + (float4(-1.0f,-0.5f, 1.0f,-0.5f) * inTEX1.xyyx);\n" + "OUT.vTexCoord2 = inTEX0.xyyx + (float4( 1.0f, 0.5f,-1.0f, 0.5f) * inTEX1.xyyx);\n" + "OUT.vTexCoord3 = inTEX2;\n" + "return OUT;\n" + "}\n"); + SimpleVertexShader[2] = D3D::CompileAndCreateVertexShader(vProg, (int)strlen(vProg)); + + Clear(); + delete [] vProg; + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + SETSTAT(stats.numVertexShadersCreated, 0); + SETSTAT(stats.numVertexShadersAlive, 0); + + char cache_filename[MAX_PATH]; + sprintf(cache_filename, "%sdx9-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id); + VertexShaderCacheInserter inserter; + int read_items = g_vs_disk_cache.OpenAndRead(cache_filename, &inserter); +} + +void VertexShaderCache::Clear() +{ + VSCache::iterator + iter = vshaders.begin(), + vsend = vshaders.end(); + for (; iter != vsend; ++iter) + iter->second.Destroy(); + + vshaders.clear(); + + memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); +} + +VertexShaderCache::~VertexShaderCache() +{ + for (int i = 0; i < MAX_SSAA_SHADERS; i++) + { + if (SimpleVertexShader[i]) + SimpleVertexShader[i]->Release(); + SimpleVertexShader[i] = NULL; + } + + if (ClearVertexShader) + ClearVertexShader->Release(); + + ClearVertexShader = NULL; + + g_vs_disk_cache.Sync(); + g_vs_disk_cache.Close(); +} + +bool VertexShaderCache::SetShader(u32 components) +{ + DVSTARTPROFILE(); + + VERTEXSHADERUID uid; + GetVertexShaderId(&uid, components); + if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + { + if (vshaders[uid].shader) + return true; + else + return false; + } + memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + + VSCache::iterator iter; + iter = vshaders.find(uid); + if (iter != vshaders.end()) + { + iter->second.frameCount = frameCount; + const VSCacheEntry &entry = iter->second; + last_entry = &entry; + + //DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); + if (entry.shader) + { + D3D::SetVertexShader(entry.shader); + return true; + } + else + return false; + } + + const char *code = GenerateVertexShaderCode(components, API_D3D9); + u8 *bytecode; + int bytecodelen; + if (!D3D::CompileVertexShader(code, (int)strlen(code), &bytecode, &bytecodelen)) + { + if (g_ActiveConfig.bShowShaderErrors) + { + PanicAlert("Failed to compile Vertex Shader:\n\n%s", code); + } + return false; + } + g_vs_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen); + g_vs_disk_cache.Sync(); + + bool result = InsertByteCode(uid, bytecode, bytecodelen, true); + delete [] bytecode; + return result; +} + +bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) { + LPDIRECT3DVERTEXSHADER9 shader = D3D::CreateVertexShaderFromByteCode(bytecode, bytecodelen); + + // Make an entry in the table + VSCacheEntry entry; + entry.shader = shader; + entry.frameCount = frameCount; + + vshaders[uid] = entry; + last_entry = &vshaders[uid]; + if (!shader) + return false; + + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size()); + if (activate) + { + D3D::SetVertexShader(shader); + return true; + } + return false; +} + +#if defined(_DEBUG) || defined(DEBUGFAST) +std::string VertexShaderCache::GetCurrentShaderCode() +{ + return "(N/A)\n"; +} +#endif + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.h index ca22125ae1..497a7c0ed1 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/DX9/DX9_VertexShaderCache.h @@ -1,81 +1,81 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _VERTEXSHADERCACHE_H -#define _VERTEXSHADERCACHE_H - -#include "DX9_D3DBase.h" - -#include -#include - -#include "DX9_D3DBase.h" -#include "VertexShaderGen.h" - -#include "../VertexShaderCache.h" - -namespace DX9 -{ - -class VertexShaderCache : public ::VertexShaderCacheBase -{ -private: - struct VSCacheEntry - { - LPDIRECT3DVERTEXSHADER9 shader; - int frameCount; -#if defined(_DEBUG) || defined(DEBUGFAST) - std::string code; -#endif - VSCacheEntry() : shader(NULL), frameCount(0) {} - void Destroy() - { - if (shader) - shader->Release(); - shader = NULL; - } - }; - - typedef std::map VSCache; - - static VSCache vshaders; - static const VSCacheEntry *last_entry; - static void Clear(); - -public: - VertexShaderCache(); - ~VertexShaderCache(); - - void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetVSConstant4fv(unsigned int const_number, const float *f); - void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f); - void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f); - - bool SetShader(u32 components); - - static LPDIRECT3DVERTEXSHADER9 GetSimpleVertexShader(int level); - static LPDIRECT3DVERTEXSHADER9 GetClearVertexShader(); - static bool InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate); -#if defined(_DEBUG) || defined(DEBUGFAST) - static std::string GetCurrentShaderCode(); -#endif - static LPDIRECT3DVERTEXSHADER9 CompileCgShader(const char *pstrprogram); -}; - -} - -#endif // _VERTEXSHADERCACHE_H +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _VERTEXSHADERCACHE_H +#define _VERTEXSHADERCACHE_H + +#include "DX9_D3DBase.h" + +#include +#include + +#include "DX9_D3DBase.h" +#include "VertexShaderGen.h" + +#include "../VertexShaderCache.h" + +namespace DX9 +{ + +class VertexShaderCache : public ::VertexShaderCacheBase +{ +private: + struct VSCacheEntry + { + LPDIRECT3DVERTEXSHADER9 shader; + int frameCount; +#if defined(_DEBUG) || defined(DEBUGFAST) + std::string code; +#endif + VSCacheEntry() : shader(NULL), frameCount(0) {} + void Destroy() + { + if (shader) + shader->Release(); + shader = NULL; + } + }; + + typedef std::map VSCache; + + static VSCache vshaders; + static const VSCacheEntry *last_entry; + static void Clear(); + +public: + VertexShaderCache(); + ~VertexShaderCache(); + + void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetVSConstant4fv(unsigned int const_number, const float *f); + void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f); + void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f); + + bool SetShader(u32 components); + + static LPDIRECT3DVERTEXSHADER9 GetSimpleVertexShader(int level); + static LPDIRECT3DVERTEXSHADER9 GetClearVertexShader(); + static bool InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate); +#if defined(_DEBUG) || defined(DEBUGFAST) + static std::string GetCurrentShaderCode(); +#endif + static LPDIRECT3DVERTEXSHADER9 CompileCgShader(const char *pstrprogram); +}; + +} + +#endif // _VERTEXSHADERCACHE_H diff --git a/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.cpp b/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.cpp index 0fed997192..1cbf21952a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.cpp @@ -1,233 +1,233 @@ - -#include - -// VideoCommon -#include "VideoConfig.h" -#include "Fifo.h" - -#include "EmuWindow.h" - -int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; - -namespace EmuWindow -{ - -HWND m_hWnd = NULL; -HWND m_hParent = NULL; -HINSTANCE m_hInstance = NULL; -WNDCLASSEX wndClass; -const TCHAR m_szClassName[] = _T("DolphinEmuWnd"); -int g_winstyle; -static volatile bool s_sizing; - -bool IsSizing() -{ - return s_sizing; -} - -HWND GetWnd() -{ - return m_hWnd; -} - -HWND GetParentWnd() -{ - return m_hParent; -} - -// --------------------------------------------------------------------- -// KeyDown events -// ------------- -void OnKeyDown(WPARAM wParam) -{ - switch (LOWORD( wParam )) - { - case '3': // OSD keys - case '4': - case '5': - case '6': - case '7': - if (g_Config.bOSDHotKey) - OSDMenu(wParam); - break; - } -} -// --------------------------------------------------------------------- - -LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) -{ - switch( iMsg ) - { - case WM_PAINT: - { - HDC hdc; - PAINTSTRUCT ps; - hdc = BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_ENTERSIZEMOVE: - s_sizing = true; - break; - - case WM_EXITSIZEMOVE: - s_sizing = false; - break; - - /* Post thes mouse events to the main window, it's nessesary because in difference to the - keyboard inputs these events only appear here, not in the parent window or any other WndProc()*/ - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_LBUTTONDBLCLK: - PostMessage(GetParentWnd(), iMsg, wParam, lParam); - break; - - case WM_CLOSE: - // When the user closes the window, we post an event to the main window to call Stop() - // Which then handles all the necessary steps to Shutdown the core + the plugins - if (m_hParent == NULL) - PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0); - break; - - case WM_USER: - if (wParam == WM_USER_KEYDOWN) - OnKeyDown(lParam); - else if (wParam == WIIMOTE_DISCONNECT) - PostMessage(m_hParent, WM_USER, wParam, lParam); - break; - - case WM_SYSCOMMAND: - switch (wParam) - { - case SC_SCREENSAVE: - case SC_MONITORPOWER: - break; - default: - return DefWindowProc(hWnd, iMsg, wParam, lParam); - } - break; - - case WM_SETCURSOR: - PostMessage(m_hParent, WM_USER, WM_USER_SETCURSOR, 0); - return true; - break; - - default: - return DefWindowProc(hWnd, iMsg, wParam, lParam); - } - return 0; -} - -// --------------------------------------------------------------------- -// OSD Menu -// ------------- -// Let's begin with 3 since 1 and 2 are default Wii keys -// ------------- -void OSDMenu(WPARAM wParam) -{ - switch( LOWORD( wParam )) - { - //case '3': - // OSDChoice = 1; - // // Toggle native resolution - // OSDInternalW = D3D::GetBackBufferWidth(); - // OSDInternalH = D3D::GetBackBufferHeight(); - // break; - case '4': - OSDChoice = 2; - // Toggle aspect ratio - g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; - break; - case '5': - OSDChoice = 3; - PanicAlert("Toggling EFB copy not implemented!\n"); - break; - case '6': - OSDChoice = 4; - g_Config.bDisableFog = !g_Config.bDisableFog; - break; - case '7': - OSDChoice = 5; - g_Config.bDisableLighting = !g_Config.bDisableLighting; - break; - } -} - -HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title) -{ - wndClass.cbSize = sizeof( wndClass ); - wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; - wndClass.lpfnWndProc = WndProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 0; - wndClass.hInstance = hInstance; - wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION ); - wndClass.hCursor = NULL; - wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); - wndClass.lpszMenuName = NULL; - wndClass.lpszClassName = m_szClassName; - wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); - - m_hInstance = hInstance; - RegisterClassEx( &wndClass ); - - m_hParent = parent; - - m_hWnd = CreateWindow(m_szClassName, title, WS_CHILD, - 0, 0, width, height, m_hParent, NULL, hInstance, NULL); - - return m_hWnd; -} - -void Show() -{ - ShowWindow(m_hWnd, SW_SHOW); - BringWindowToTop(m_hWnd); - UpdateWindow(m_hWnd); - SetFocus(m_hParent); -} - -HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title) -{ - // TODO: - // 1. Remove redundant window manipulation, - // 2. Make DX11 in fullscreen can be overlapped by other dialogs - // 3. Request window sizes which actually make the client area map to a common resolution - HWND Ret; - int x=0, y=0, width=640, height=480; - g_VideoInitialize.pRequestWindowSize(x, y, width, height); - - Ret = OpenWindow(hParent, hInstance, width, height, title); - - if (Ret) - { - Show(); - } - return Ret; -} - -void Close() -{ - if (m_hParent == NULL) - DestroyWindow(m_hWnd); - UnregisterClass(m_szClassName, m_hInstance); -} - -void SetSize(int width, int height) -{ - RECT rc = {0, 0, width, height}; - DWORD style = GetWindowLong(m_hWnd, GWL_STYLE); - AdjustWindowRect(&rc, style, false); - - int w = rc.right - rc.left; - int h = rc.bottom - rc.top; - - rc.left = (1280 - w)/2; - rc.right = rc.left + w; - rc.top = (1024 - h)/2; - rc.bottom = rc.top + h; - MoveWindow(m_hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE); -} - -} + +#include + +// VideoCommon +#include "VideoConfig.h" +#include "Fifo.h" + +#include "EmuWindow.h" + +int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; + +namespace EmuWindow +{ + +HWND m_hWnd = NULL; +HWND m_hParent = NULL; +HINSTANCE m_hInstance = NULL; +WNDCLASSEX wndClass; +const TCHAR m_szClassName[] = _T("DolphinEmuWnd"); +int g_winstyle; +static volatile bool s_sizing; + +bool IsSizing() +{ + return s_sizing; +} + +HWND GetWnd() +{ + return m_hWnd; +} + +HWND GetParentWnd() +{ + return m_hParent; +} + +// --------------------------------------------------------------------- +// KeyDown events +// ------------- +void OnKeyDown(WPARAM wParam) +{ + switch (LOWORD( wParam )) + { + case '3': // OSD keys + case '4': + case '5': + case '6': + case '7': + if (g_Config.bOSDHotKey) + OSDMenu(wParam); + break; + } +} +// --------------------------------------------------------------------- + +LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) +{ + switch( iMsg ) + { + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + } + break; + + case WM_ENTERSIZEMOVE: + s_sizing = true; + break; + + case WM_EXITSIZEMOVE: + s_sizing = false; + break; + + /* Post thes mouse events to the main window, it's nessesary because in difference to the + keyboard inputs these events only appear here, not in the parent window or any other WndProc()*/ + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + PostMessage(GetParentWnd(), iMsg, wParam, lParam); + break; + + case WM_CLOSE: + // When the user closes the window, we post an event to the main window to call Stop() + // Which then handles all the necessary steps to Shutdown the core + the plugins + if (m_hParent == NULL) + PostMessage(m_hParent, WM_USER, WM_USER_STOP, 0); + break; + + case WM_USER: + if (wParam == WM_USER_KEYDOWN) + OnKeyDown(lParam); + else if (wParam == WIIMOTE_DISCONNECT) + PostMessage(m_hParent, WM_USER, wParam, lParam); + break; + + case WM_SYSCOMMAND: + switch (wParam) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + break; + default: + return DefWindowProc(hWnd, iMsg, wParam, lParam); + } + break; + + case WM_SETCURSOR: + PostMessage(m_hParent, WM_USER, WM_USER_SETCURSOR, 0); + return true; + break; + + default: + return DefWindowProc(hWnd, iMsg, wParam, lParam); + } + return 0; +} + +// --------------------------------------------------------------------- +// OSD Menu +// ------------- +// Let's begin with 3 since 1 and 2 are default Wii keys +// ------------- +void OSDMenu(WPARAM wParam) +{ + switch( LOWORD( wParam )) + { + //case '3': + // OSDChoice = 1; + // // Toggle native resolution + // OSDInternalW = D3D::GetBackBufferWidth(); + // OSDInternalH = D3D::GetBackBufferHeight(); + // break; + case '4': + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + break; + case '5': + OSDChoice = 3; + PanicAlert("Toggling EFB copy not implemented!\n"); + break; + case '6': + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + break; + case '7': + OSDChoice = 5; + g_Config.bDisableLighting = !g_Config.bDisableLighting; + break; + } +} + +HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const TCHAR *title) +{ + wndClass.cbSize = sizeof( wndClass ); + wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; + wndClass.lpfnWndProc = WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = hInstance; + wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION ); + wndClass.hCursor = NULL; + wndClass.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = m_szClassName; + wndClass.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); + + m_hInstance = hInstance; + RegisterClassEx( &wndClass ); + + m_hParent = parent; + + m_hWnd = CreateWindow(m_szClassName, title, WS_CHILD, + 0, 0, width, height, m_hParent, NULL, hInstance, NULL); + + return m_hWnd; +} + +void Show() +{ + ShowWindow(m_hWnd, SW_SHOW); + BringWindowToTop(m_hWnd); + UpdateWindow(m_hWnd); + SetFocus(m_hParent); +} + +HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title) +{ + // TODO: + // 1. Remove redundant window manipulation, + // 2. Make DX11 in fullscreen can be overlapped by other dialogs + // 3. Request window sizes which actually make the client area map to a common resolution + HWND Ret; + int x=0, y=0, width=640, height=480; + g_VideoInitialize.pRequestWindowSize(x, y, width, height); + + Ret = OpenWindow(hParent, hInstance, width, height, title); + + if (Ret) + { + Show(); + } + return Ret; +} + +void Close() +{ + if (m_hParent == NULL) + DestroyWindow(m_hWnd); + UnregisterClass(m_szClassName, m_hInstance); +} + +void SetSize(int width, int height) +{ + RECT rc = {0, 0, width, height}; + DWORD style = GetWindowLong(m_hWnd, GWL_STYLE); + AdjustWindowRect(&rc, style, false); + + int w = rc.right - rc.left; + int h = rc.bottom - rc.top; + + rc.left = (1280 - w)/2; + rc.right = rc.left + w; + rc.top = (1024 - h)/2; + rc.bottom = rc.top + h; + MoveWindow(m_hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, TRUE); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.h b/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.h index a352e12230..9e3bb4f74c 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/EmuWindow.h @@ -1,21 +1,21 @@ - -#ifndef _EMUWINDOW_H_ -#define _EMUWINDOW_H_ - -#include - -namespace EmuWindow -{ - -HWND GetWnd(); -HWND GetParentWnd(); -HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR* title); -void Show(); -void Close(); -void SetSize(int displayWidth, int displayHeight); -bool IsSizing(); -void OSDMenu(WPARAM wParam); - -} - -#endif + +#ifndef _EMUWINDOW_H_ +#define _EMUWINDOW_H_ + +#include + +namespace EmuWindow +{ + +HWND GetWnd(); +HWND GetParentWnd(); +HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR* title); +void Show(); +void Close(); +void SetSize(int displayWidth, int displayHeight); +bool IsSizing(); +void OSDMenu(WPARAM wParam); + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp index 023b9edf0c..b345ba6f3e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.cpp @@ -1,216 +1,216 @@ - -#include "FramebufferManager.h" - -#include "VideoConfig.h" -#include "Renderer.h" - -#include "Main.h" - -FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode - -const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[]; - -FramebufferManagerBase::~FramebufferManagerBase() -{ - VirtualXFBListType::iterator - it = m_virtualXFBList.begin(), - vlend = m_virtualXFBList.end(); - for (; it != vlend; ++it) - delete it->xfbSource; -} - -const XFBSourceBase** FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) -{ - //if (g_ActiveConfig.bUseRealXFB) - // return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); - //else - return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); -} - -inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) -{ - return !((aLower >= bUpper) || (bLower >= aUpper)); -} - -void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - //if (g_ActiveConfig.bUseRealXFB) - // copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc); - //else - copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc); -} - -void FramebufferManagerBase::replaceVirtualXFB() -{ - VirtualXFBListType::iterator - it = m_virtualXFBList.begin(), - vlend = m_virtualXFBList.end(); - - VirtualXFB *vxfb = &*it; - - const s32 srcLower = vxfb->xfbAddr; - const s32 srcUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; - const s32 lineSize = 2 * vxfb->xfbWidth; - - while (++it != vlend) - { - vxfb = &*it; - - const s32 dstLower = vxfb->xfbAddr; - const s32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; - - if (dstLower >= srcLower && dstUpper <= srcUpper) - { - // invalidate the data - vxfb->xfbAddr = 0; - vxfb->xfbHeight = 0; - vxfb->xfbWidth = 0; - } - else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - const s32 upperOverlap = (srcUpper - dstLower) / lineSize; - const s32 lowerOverlap = (dstUpper - srcLower) / lineSize; - - if (upperOverlap > 0 && lowerOverlap < 0) - { - vxfb->xfbAddr += lineSize * upperOverlap; - vxfb->xfbHeight -= upperOverlap; - } - else if (lowerOverlap > 0) - { - vxfb->xfbHeight -= lowerOverlap; - } - } - } -} - -FramebufferManagerBase::VirtualXFBListType::iterator -FramebufferManagerBase::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) -{ - const u32 srcLower = xfbAddr; - const u32 srcUpper = xfbAddr + 2 * width * height; - - VirtualXFBListType::iterator - it = m_virtualXFBList.begin(), - vlend = m_virtualXFBList.end(); - for (; it != vlend; ++it) - { - const VirtualXFB &vxfb = *it; - - const u32 dstLower = vxfb.xfbAddr; - const u32 dstUpper = vxfb.xfbAddr + 2 * vxfb.xfbWidth * vxfb.xfbHeight; - - if (dstLower >= srcLower && dstUpper <= srcUpper) - return it; - } - - // That address is not in the Virtual XFB list. - return m_virtualXFBList.end(); -} - -void FramebufferManagerBase::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - const VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); - - VirtualXFB *vxfb = NULL; - - if (m_virtualXFBList.end() == it) - { - if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) - { - PanicAlert("Requested creating a new virtual XFB although the maximum number has already been reached! Report this to the devs"); - return; - // TODO, possible alternative to failing: just delete the oldest virtual XFB: - // delete m_virtualXFBList.back().xfbSource; - // m_virtualXFBList.pop_back(); - } - else - { - // create a new Virtual XFB and place it at the front of the list - VirtualXFB v; - m_virtualXFBList.push_front(v); - vxfb = &m_virtualXFBList.front(); - } - } - else - { - vxfb = &*it; - delete vxfb->xfbSource; - } - - vxfb->xfbAddr = xfbAddr; - vxfb->xfbWidth = fbWidth; - vxfb->xfbHeight = fbHeight; - - const float scaleX = RendererBase::GetXFBScaleX(); - const float scaleY = RendererBase::GetXFBScaleY(); - - TargetRectangle targetSource; - targetSource.top = (int)(sourceRc.top * scaleY); - targetSource.bottom = (int)(sourceRc.bottom * scaleY); - targetSource.left = (int)(sourceRc.left * scaleX); - targetSource.right = (int)(sourceRc.right * scaleX); - - const unsigned int target_width = targetSource.right - targetSource.left; - const unsigned int target_height = targetSource.bottom - targetSource.top; - - vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height); - if (NULL == vxfb->xfbSource) - { - PanicAlert("Failed to create virtual XFB"); - return; - } - - // why do both of these have a height/width/addr ? - vxfb->xfbSource->srcAddr = xfbAddr; - vxfb->xfbSource->srcWidth = fbWidth; - vxfb->xfbSource->srcHeight = fbHeight; - - vxfb->xfbSource->texWidth = target_width; - vxfb->xfbSource->texHeight = target_height; - - if (m_virtualXFBList.end() != it) - { - // move this Virtual XFB to the front of the list. - m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); - - // keep stale XFB data from being used - replaceVirtualXFB(); - } - - g_renderer->ResetAPIState(); // reset any game specific settings - - vxfb->xfbSource->CopyEFB(RendererBase::ConvertEFBRectangle(sourceRc)); - - g_renderer->RestoreAPIState(); -} - -const XFBSourceBase** FramebufferManagerBase::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) -{ - xfbCount = 0; - - if (0 == m_virtualXFBList.size()) // no Virtual XFBs available - return NULL; - - u32 srcLower = xfbAddr; - u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; - - VirtualXFBListType::reverse_iterator - it = m_virtualXFBList.rbegin(), - vlend = m_virtualXFBList.rend(); - for (; it != vlend; ++it) - { - VirtualXFB* vxfb = &*it; - - u32 dstLower = vxfb->xfbAddr; - u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; - - if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - m_overlappingXFBArray[xfbCount] = vxfb->xfbSource; - xfbCount++; - } - } - - return &m_overlappingXFBArray[0]; -} + +#include "FramebufferManager.h" + +#include "VideoConfig.h" +#include "Renderer.h" + +#include "Main.h" + +FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode + +const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[]; + +FramebufferManagerBase::~FramebufferManagerBase() +{ + VirtualXFBListType::iterator + it = m_virtualXFBList.begin(), + vlend = m_virtualXFBList.end(); + for (; it != vlend; ++it) + delete it->xfbSource; +} + +const XFBSourceBase** FramebufferManagerBase::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + //if (g_ActiveConfig.bUseRealXFB) + // return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); + //else + return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); +} + +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return !((aLower >= bUpper) || (bLower >= aUpper)); +} + +void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + //if (g_ActiveConfig.bUseRealXFB) + // copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc); + //else + copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc); +} + +void FramebufferManagerBase::replaceVirtualXFB() +{ + VirtualXFBListType::iterator + it = m_virtualXFBList.begin(), + vlend = m_virtualXFBList.end(); + + VirtualXFB *vxfb = &*it; + + const s32 srcLower = vxfb->xfbAddr; + const s32 srcUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; + const s32 lineSize = 2 * vxfb->xfbWidth; + + while (++it != vlend) + { + vxfb = &*it; + + const s32 dstLower = vxfb->xfbAddr; + const s32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; + + if (dstLower >= srcLower && dstUpper <= srcUpper) + { + // invalidate the data + vxfb->xfbAddr = 0; + vxfb->xfbHeight = 0; + vxfb->xfbWidth = 0; + } + else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + const s32 upperOverlap = (srcUpper - dstLower) / lineSize; + const s32 lowerOverlap = (dstUpper - srcLower) / lineSize; + + if (upperOverlap > 0 && lowerOverlap < 0) + { + vxfb->xfbAddr += lineSize * upperOverlap; + vxfb->xfbHeight -= upperOverlap; + } + else if (lowerOverlap > 0) + { + vxfb->xfbHeight -= lowerOverlap; + } + } + } +} + +FramebufferManagerBase::VirtualXFBListType::iterator +FramebufferManagerBase::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) +{ + const u32 srcLower = xfbAddr; + const u32 srcUpper = xfbAddr + 2 * width * height; + + VirtualXFBListType::iterator + it = m_virtualXFBList.begin(), + vlend = m_virtualXFBList.end(); + for (; it != vlend; ++it) + { + const VirtualXFB &vxfb = *it; + + const u32 dstLower = vxfb.xfbAddr; + const u32 dstUpper = vxfb.xfbAddr + 2 * vxfb.xfbWidth * vxfb.xfbHeight; + + if (dstLower >= srcLower && dstUpper <= srcUpper) + return it; + } + + // That address is not in the Virtual XFB list. + return m_virtualXFBList.end(); +} + +void FramebufferManagerBase::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + const VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); + + VirtualXFB *vxfb = NULL; + + if (m_virtualXFBList.end() == it) + { + if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) + { + PanicAlert("Requested creating a new virtual XFB although the maximum number has already been reached! Report this to the devs"); + return; + // TODO, possible alternative to failing: just delete the oldest virtual XFB: + // delete m_virtualXFBList.back().xfbSource; + // m_virtualXFBList.pop_back(); + } + else + { + // create a new Virtual XFB and place it at the front of the list + VirtualXFB v; + m_virtualXFBList.push_front(v); + vxfb = &m_virtualXFBList.front(); + } + } + else + { + vxfb = &*it; + delete vxfb->xfbSource; + } + + vxfb->xfbAddr = xfbAddr; + vxfb->xfbWidth = fbWidth; + vxfb->xfbHeight = fbHeight; + + const float scaleX = RendererBase::GetXFBScaleX(); + const float scaleY = RendererBase::GetXFBScaleY(); + + TargetRectangle targetSource; + targetSource.top = (int)(sourceRc.top * scaleY); + targetSource.bottom = (int)(sourceRc.bottom * scaleY); + targetSource.left = (int)(sourceRc.left * scaleX); + targetSource.right = (int)(sourceRc.right * scaleX); + + const unsigned int target_width = targetSource.right - targetSource.left; + const unsigned int target_height = targetSource.bottom - targetSource.top; + + vxfb->xfbSource = g_framebuffer_manager->CreateXFBSource(target_width, target_height); + if (NULL == vxfb->xfbSource) + { + PanicAlert("Failed to create virtual XFB"); + return; + } + + // why do both of these have a height/width/addr ? + vxfb->xfbSource->srcAddr = xfbAddr; + vxfb->xfbSource->srcWidth = fbWidth; + vxfb->xfbSource->srcHeight = fbHeight; + + vxfb->xfbSource->texWidth = target_width; + vxfb->xfbSource->texHeight = target_height; + + if (m_virtualXFBList.end() != it) + { + // move this Virtual XFB to the front of the list. + m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); + + // keep stale XFB data from being used + replaceVirtualXFB(); + } + + g_renderer->ResetAPIState(); // reset any game specific settings + + vxfb->xfbSource->CopyEFB(RendererBase::ConvertEFBRectangle(sourceRc)); + + g_renderer->RestoreAPIState(); +} + +const XFBSourceBase** FramebufferManagerBase::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + xfbCount = 0; + + if (0 == m_virtualXFBList.size()) // no Virtual XFBs available + return NULL; + + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; + + VirtualXFBListType::reverse_iterator + it = m_virtualXFBList.rbegin(), + vlend = m_virtualXFBList.rend(); + for (; it != vlend; ++it) + { + VirtualXFB* vxfb = &*it; + + u32 dstLower = vxfb->xfbAddr; + u32 dstUpper = vxfb->xfbAddr + 2 * vxfb->xfbWidth * vxfb->xfbHeight; + + if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + m_overlappingXFBArray[xfbCount] = vxfb->xfbSource; + xfbCount++; + } + } + + return &m_overlappingXFBArray[0]; +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.h index 1821560e81..554aba7463 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/FramebufferManager.h @@ -1,71 +1,71 @@ - -#ifndef _FRAMEBUFFERMANAGER_H_ -#define _FRAMEBUFFERMANAGER_H_ - -#include - -#include "CommonTypes.h" -#include "VideoCommon.h" - -struct XFBSourceBase -{ - u32 srcAddr; - u32 srcWidth; - u32 srcHeight; - - unsigned int texWidth; - unsigned int texHeight; - - virtual void CopyEFB(const TargetRectangle& efbSource) = 0; - - virtual ~XFBSourceBase() {} - -protected: - XFBSourceBase() : srcAddr(0), srcWidth(0), srcHeight(0), texWidth(0), texHeight(0) {} -}; - -class FramebufferManagerBase -{ -public: - - enum - { - MAX_VIRTUAL_XFB = 8, - }; - - virtual ~FramebufferManagerBase(); - - //virtual void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) = 0; - //virtual void Shutdown() = 0; - - static void replaceVirtualXFB(); - - static void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - - static const XFBSourceBase** GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); - static const XFBSourceBase** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); - -//protected: - struct VirtualXFB - { - // Address and size in GameCube RAM - u32 xfbAddr; - u32 xfbWidth; - u32 xfbHeight; - - XFBSourceBase *xfbSource; - }; - - virtual XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height) = 0; - - typedef std::list VirtualXFBListType; - static VirtualXFBListType m_virtualXFBList; // used in virtual XFB mode - - static VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); - - static void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - - static const XFBSourceBase* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; -}; - -#endif + +#ifndef _FRAMEBUFFERMANAGER_H_ +#define _FRAMEBUFFERMANAGER_H_ + +#include + +#include "CommonTypes.h" +#include "VideoCommon.h" + +struct XFBSourceBase +{ + u32 srcAddr; + u32 srcWidth; + u32 srcHeight; + + unsigned int texWidth; + unsigned int texHeight; + + virtual void CopyEFB(const TargetRectangle& efbSource) = 0; + + virtual ~XFBSourceBase() {} + +protected: + XFBSourceBase() : srcAddr(0), srcWidth(0), srcHeight(0), texWidth(0), texHeight(0) {} +}; + +class FramebufferManagerBase +{ +public: + + enum + { + MAX_VIRTUAL_XFB = 8, + }; + + virtual ~FramebufferManagerBase(); + + //virtual void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) = 0; + //virtual void Shutdown() = 0; + + static void replaceVirtualXFB(); + + static void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + + static const XFBSourceBase** GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + static const XFBSourceBase** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + +//protected: + struct VirtualXFB + { + // Address and size in GameCube RAM + u32 xfbAddr; + u32 xfbWidth; + u32 xfbHeight; + + XFBSourceBase *xfbSource; + }; + + virtual XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height) = 0; + + typedef std::list VirtualXFBListType; + static VirtualXFBListType m_virtualXFBList; // used in virtual XFB mode + + static VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); + + static void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + + static const XFBSourceBase* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/Main.cpp b/Source/Plugins/Plugin_VideoMerge/Src/Main.cpp index 70d514805a..290fc607c2 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/Main.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/Main.cpp @@ -1,626 +1,626 @@ - -#include "pluginspecs_video.h" - -// TODO: temporary, just used in Video_Prepare -// comment out to use (try to use :p) OpenGL -#define USE_DX11 - -#include -#include - -// Common -#include "Common.h" -#include "Atomic.h" -#include "Thread.h" -#include "LogManager.h" - -// VideoCommon -#include "VideoConfig.h" -#include "Fifo.h" -#include "OpcodeDecoding.h" -#include "BPStructs.h" -#include "VertexLoaderManager.h" -#include "VertexShaderManager.h" -#include "PixelShaderManager.h" -#include "CommandProcessor.h" -#include "PixelEngine.h" -#include "OnScreenDisplay.h" -#include "VideoState.h" -#include "XFBConvert.h" -#include "DLCache.h" - -// internal crap -#include "Renderer.h" -#include "TextureCache.h" -#include "VertexManager.h" -#include "VertexShaderCache.h" -#include "PixelShaderCache.h" -#include "FramebufferManager.h" - -#ifdef _WIN32 - -#include "DX11/DX11_TextureCache.h" -#include "DX11/DX11_VertexShaderCache.h" -#include "DX11/DX11_PixelShaderCache.h" -#include "DX11/DX11_Render.h" -#include "DX11/DX11_VertexManager.h" - -#include "DX9/DX9_TextureCache.h" -#include "DX9/DX9_VertexShaderCache.h" -#include "DX9/DX9_PixelShaderCache.h" -#include "DX9/DX9_Render.h" -#include "DX9/DX9_VertexManager.h" - -#endif - -#include "OGL/OGL_TextureCache.h" -#include "OGL/OGL_VertexShaderCache.h" -#include "OGL/OGL_PixelShaderCache.h" -#include "OGL/OGL_Render.h" -#include "OGL/OGL_VertexManager.h" - -#include "EmuWindow.h" - -// TODO: ifdef wx this -#include "VideoConfigDiag.h" - -#include "Main.h" - -#define PLUGIN_NAME "Dolphin Video Merge [broken]" -#if defined(DEBUGFAST) -#define PLUGIN_FULL_NAME PLUGIN_NAME" (DebugFast)" -#elif defined(_DEBUG) -#define PLUGIN_FULL_NAME PLUGIN_NAME" (Debug)" -#else -#define PLUGIN_FULL_NAME PLUGIN_NAME -#endif - -HINSTANCE g_hInstance = NULL; -SVideoInitialize g_VideoInitialize; -PLUGIN_GLOBALS *g_globals = NULL; - -const char* const g_gfxapi_names[] = -{ - "Software", - "OpenGL", - "Direct3D 9", - "Direct3D 11", -}; - -#define INI_NAME "gfx_new.ini" - -// TODO: save to ini file -// TODO: move to VideoConfig or something -int g_gfxapi = 3; - -// shits -RendererBase *g_renderer; -TextureCacheBase *g_texture_cache; -VertexManagerBase *g_vertex_manager; -VertexShaderCacheBase* g_vertex_shader_cache; -PixelShaderCacheBase* g_pixel_shader_cache; -FramebufferManagerBase* g_framebuffer_manager; - -static bool s_PluginInitialized = false; -volatile u32 s_swapRequested = false; -static u32 s_efbAccessRequested = false; -static volatile u32 s_FifoShuttingDown = false; - -int frameCount; - -#if defined(HAVE_WX) && HAVE_WX -class wxDLLApp : public wxApp -{ - bool OnInit() - { - return true; - } -}; -IMPLEMENT_APP_NO_MAIN(wxDLLApp) -WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst); -#endif - -#ifdef _WIN32 -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - wxSetInstance(hinstDLL); - wxInitialize(); - break; - - case DLL_PROCESS_DETACH: - wxUninitialize(); - break; - - default: - break; - } - - g_hInstance = hinstDLL; - return true; -} -#endif - -static volatile struct -{ - u32 xfbAddr; - FieldType field; - u32 fbWidth; - u32 fbHeight; -} s_beginFieldArgs; - -static inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) -{ - return !((aLower >= bUpper) || (bLower >= aUpper)); -} - -// Run from the graphics thread (from Fifo.cpp) -void VideoFifo_CheckSwapRequest() -{ - if(g_ActiveConfig.bUseXFB) - { - if (Common::AtomicLoadAcquire(s_swapRequested)) - { - EFBRectangle rc; - g_renderer->Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, - s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight, rc); - Common::AtomicStoreRelease(s_swapRequested, false); - } - } -} - -// Run from the graphics thread (from Fifo.cpp) -void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight) -{ - if (g_ActiveConfig.bUseXFB) - { - if(Common::AtomicLoadAcquire(s_swapRequested)) - { - u32 aLower = xfbAddr; - u32 aUpper = xfbAddr + 2 * fbWidth * fbHeight; - u32 bLower = s_beginFieldArgs.xfbAddr; - u32 bUpper = s_beginFieldArgs.xfbAddr + 2 * s_beginFieldArgs.fbWidth * s_beginFieldArgs.fbHeight; - - if (addrRangesOverlap(aLower, aUpper, bLower, bUpper)) - VideoFifo_CheckSwapRequest(); - } - } -} - -static struct -{ - EFBAccessType type; - u32 x; - u32 y; - u32 Data; -} s_accessEFBArgs; - -static u32 s_AccessEFBResult = 0; - -void VideoFifo_CheckEFBAccess() -{ - if (Common::AtomicLoadAcquire(s_efbAccessRequested)) - { - s_AccessEFBResult = g_renderer->AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); - - Common::AtomicStoreRelease(s_efbAccessRequested, false); - } -} - -void VideoFifo_CheckAsyncRequest() -{ - VideoFifo_CheckSwapRequest(); - VideoFifo_CheckEFBAccess(); -} - -unsigned int Callback_PeekMessages() -{ - MSG msg; - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - return 0; - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return 1; -} - -void UpdateFPSDisplay(const char *text) -{ - char temp[512]; - sprintf_s(temp, 512, "SVN R%s: DX11: %s", svn_rev_str, text); - SetWindowTextA(EmuWindow::GetWnd(), temp); -} - -// GLOBAL I N T E R F A C E -// ____________________________________________________________________________ -// Function: GetDllInfo -// Purpose: This function allows the emulator to gather information -// about the DLL by filling in the PluginInfo structure. -// input: A pointer to a PLUGIN_INFO structure that needs to be -// filled by the function. (see def above) -// output: none -// -void GetDllInfo(PLUGIN_INFO* _pPluginInfo) -{ - memcpy(_pPluginInfo->Name, PLUGIN_FULL_NAME, sizeof(PLUGIN_FULL_NAME)); - _pPluginInfo->Type = PLUGIN_TYPE_VIDEO; - _pPluginInfo->Version = 0x0100; -} - -// ___________________________________________________________________________ -// Function: DllConfig -// Purpose: This function is optional function that is provided -// to allow the user to configure the DLL -// input: A handle to the window that calls this function -// output: none -// -void DllConfig(void *_hParent) -{ -#if defined(HAVE_WX) && HAVE_WX - - VideoConfigDiag* const m_config_diag = new VideoConfigDiag((wxWindow *)_hParent); - m_config_diag->ShowModal(); - m_config_diag->Destroy(); - - g_Config.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str()); - - SLEEP(50); // hax to keep Dolphin window from staying hidden -#endif -} - -// ___________________________________________________________________________ -// Function: DllDebugger -// Purpose: Open the debugger -// input: a handle to the window that calls this function -// output: none -// -void* DllDebugger(void *_hParent, bool Show) -{ - // TODO: - return NULL; -} - -// ___________________________________________________________________________ -// Function: DllSetGlobals -// Purpose: Set the pointer for globals variables -// input: a pointer to the global struct -// output: none -// -void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals) -{ - g_globals = _pPluginGlobals; -} - -// ___________________________________________________________________________ -// Function: Initialize -// Purpose: Initialize the plugin -// input: Init -// output: none -// -void Initialize(void *init) -{ - frameCount = 0; - - g_VideoInitialize = *(SVideoInitialize*)init; - - InitXFBConvTables(); - - g_Config.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str()); - g_Config.GameIniLoad(g_globals->game_ini); - UpdateActiveConfig(); - - g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create((HWND)g_VideoInitialize.pWindowHandle, g_hInstance, _T("Loading - Please wait.")); - if (NULL == g_VideoInitialize.pWindowHandle) - { - ERROR_LOG(VIDEO, "An error has occurred while trying to create the window."); - return; - } - - g_VideoInitialize.pPeekMessages = Callback_PeekMessages; - g_VideoInitialize.pUpdateFPSDisplay = UpdateFPSDisplay; - - *(SVideoInitialize*)init = g_VideoInitialize; - - //OSD::AddMessage("Dolphin ... Video Plugin", 5000); - s_PluginInitialized = true; -} - -// ___________________________________________________________________________ -// Function: Shutdown -// Purpose: This function is called when the emulator is shutting down -// a game allowing the dll to de-initialise. -// input: none -// output: none -// -void Shutdown(void) -{ - s_efbAccessRequested = false; - s_FifoShuttingDown = false; - s_swapRequested = false; - - // VideoCommon - DLCache::Shutdown(); - CommandProcessor::Shutdown(); - PixelShaderManager::Shutdown(); - VertexShaderManager::Shutdown(); - OpcodeDecoder_Shutdown(); - VertexLoaderManager::Shutdown(); - Fifo_Shutdown(); - - // internal interfaces - EmuWindow::Close(); - - s_PluginInitialized = false; - - delete g_pixel_shader_cache; - delete g_vertex_shader_cache; - delete g_vertex_manager; - delete g_texture_cache; - delete g_renderer; -} - -// ___________________________________________________________________________ -// Function: DoState -// Purpose: Saves/load state -// input/output: ptr -// input: mode -// -void DoState(unsigned char **ptr, int mode) -{ - PanicAlert("DoState"); -} - -// ___________________________________________________________________________ -// Function: EmuStateChange -// Purpose: Notifies the plugin of a change in emulation state -// input: newState -// output: none -// -void EmuStateChange(PLUGIN_EMUSTATE newState) -{ - Fifo_RunLoop(newState == PLUGIN_EMUSTATE_PLAY); -} - -// I N T E R F A C E - - -// __________________________________________________________________________________________________ -// Function: Video_Prepare -// Purpose: This function is called from the EmuThread before the -// emulation has started. It is just for threadsensitive -// APIs like OpenGL. -// input: none -// output: none -// -void Video_Prepare(void) -{ - s_efbAccessRequested = false; - s_FifoShuttingDown = false; - s_swapRequested = false; - - switch (g_gfxapi) - { -#ifdef _WIN32 - case GFXAPI_D3D9: - g_renderer = new DX9::Renderer; - g_texture_cache = new DX9::TextureCache; - g_vertex_manager = new DX9::VertexManager; - g_vertex_shader_cache = new DX9::VertexShaderCache; - g_pixel_shader_cache = new DX9::PixelShaderCache; - break; - - case GFXAPI_D3D11: - g_renderer = new DX11::Renderer; - g_texture_cache = new DX11::TextureCache; - g_vertex_manager = new DX11::VertexManager; - g_vertex_shader_cache = new DX11::VertexShaderCache; - g_pixel_shader_cache = new DX11::PixelShaderCache; - break; -#endif - - default: - case GFXAPI_OPENGL: - g_renderer = new OGL::Renderer; - g_texture_cache = new OGL::TextureCache; - g_vertex_manager = new OGL::VertexManager; - g_vertex_shader_cache = new OGL::VertexShaderCache; - g_pixel_shader_cache = new OGL::PixelShaderCache; - break; - } - - // VideoCommon - BPInit(); - Fifo_Init(); - VertexLoaderManager::Init(); - OpcodeDecoder_Init(); - VertexShaderManager::Init(); - PixelShaderManager::Init(); - CommandProcessor::Init(); - PixelEngine::Init(); - DLCache::Init(); - - // tell the host that the window is ready - g_VideoInitialize.pCoreMessage(WM_USER_CREATE); -} - -// __________________________________________________________________________________________________ -// Function: Video_BeginField -// Purpose: When a field begins in the VI emulator, this function tells the video plugin what the -// parameters of the upcoming field are. The video plugin should make sure the previous -// field is on the player's display before returning. -// input: vi parameters of the upcoming field -// output: none -// -void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) -{ - if (s_PluginInitialized && g_ActiveConfig.bUseXFB) - { - if (g_VideoInitialize.bOnThread) - { - while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown) - //Common::SleepCurrentThread(1); - Common::YieldCPU(); - } - else - VideoFifo_CheckSwapRequest(); - s_beginFieldArgs.xfbAddr = xfbAddr; - s_beginFieldArgs.field = field; - s_beginFieldArgs.fbWidth = fbWidth; - s_beginFieldArgs.fbHeight = fbHeight; - - Common::AtomicStoreRelease(s_swapRequested, true); - } -} - -// __________________________________________________________________________________________________ -// Function: Video_EndField -// Purpose: When a field ends in the VI emulator, this function notifies the video plugin. The video -// has permission to swap the field to the player's display. -// input: none -// output: none -// -void Video_EndField() -{ - return; -} - -// __________________________________________________________________________________________________ -// Function: Video_AccessEFB -// input: type of access (r/w, z/color, ...), x coord, y coord -// output: response to the access request (ex: peek z data at specified coord) -// -u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) -{ - if (s_PluginInitialized) - { - s_accessEFBArgs.type = type; - s_accessEFBArgs.x = x; - s_accessEFBArgs.y = y; - s_accessEFBArgs.Data = InputData; - Common::AtomicStoreRelease(s_efbAccessRequested, true); - - if (g_VideoInitialize.bOnThread) - { - while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) - //Common::SleepCurrentThread(1); - Common::YieldCPU(); - } - else - VideoFifo_CheckEFBAccess(); - - return s_AccessEFBResult; - } - return 0; -} - -// __________________________________________________________________________________________________ -// Function: Video_Screenshot -// input: Filename -// output: true if all was okay -// -void Video_Screenshot(const char *_szFilename) -{ - PanicAlert("Screenshots are not yet supported."); - return; -} - -// __________________________________________________________________________________________________ -// Function: Video_EnterLoop -// Purpose: Enters the video fifo dispatch loop. This is only used in Dual Core mode. -// input: none -// output: none -// -void Video_EnterLoop() -{ - Fifo_EnterLoop(g_VideoInitialize); -} - -// __________________________________________________________________________________________________ -// Function: Video_ExitLoop -// Purpose: Exits the video dispatch loop. This is only used in Dual Core mode. -// input: none -// output: none -// -void Video_ExitLoop() -{ - Fifo_ExitLoop(); - s_FifoShuttingDown = true; -} - -// __________________________________________________________________________________________________ -// Function: Video_SetRendering -// Purpose: Sets video rendering on and off. Currently used for frame skipping -// input: Enabled toggle -// output: none -// -void Video_SetRendering(bool bEnabled) -{ - PanicAlert("SetRendering is not yet supported."); -} - -// __________________________________________________________________________________________________ -// Function: Video_AddMessage -// Purpose: Adds a message to the display queue, to be shown forthe specified time -// input: pointer to the null-terminated string, time in milliseconds -// output: none -// -void Video_AddMessage(const char* pstr, unsigned int milliseconds) -{ - return; -} - -void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address) -{ - CommandProcessor::Read16(_rReturnValue, _Address); -} - -void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address) -{ - CommandProcessor::Write16(_Data, _Address); -} - -void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address) -{ - PixelEngine::Read16(_rReturnValue, _Address); -} - -void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address) -{ - PixelEngine::Write16(_Data, _Address); -} - -void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address) -{ - PixelEngine::Write32(_Data, _Address); -} - -void Video_GatherPipeBursted(void) -{ - CommandProcessor::GatherPipeBursted(); -} - -void Video_WaitForFrameFinish(void) -{ - CommandProcessor::WaitForFrameFinish(); -} - -// __________________________________________________________________________________________________ -// Function: Video_IsFifoBusy -// Purpose: Return if the FIFO is proecessing data, that is used for sync gfx thread and emulator -// thread in CoreTiming -// input: none -// output: bool -// -bool Video_IsFifoBusy(void) -{ - return CommandProcessor::isFifoBusy; -} - -void Video_AbortFrame(void) -{ - CommandProcessor::AbortFrame(); -} + +#include "pluginspecs_video.h" + +// TODO: temporary, just used in Video_Prepare +// comment out to use (try to use :p) OpenGL +#define USE_DX11 + +#include +#include + +// Common +#include "Common.h" +#include "Atomic.h" +#include "Thread.h" +#include "LogManager.h" + +// VideoCommon +#include "VideoConfig.h" +#include "Fifo.h" +#include "OpcodeDecoding.h" +#include "BPStructs.h" +#include "VertexLoaderManager.h" +#include "VertexShaderManager.h" +#include "PixelShaderManager.h" +#include "CommandProcessor.h" +#include "PixelEngine.h" +#include "OnScreenDisplay.h" +#include "VideoState.h" +#include "XFBConvert.h" +#include "DLCache.h" + +// internal crap +#include "Renderer.h" +#include "TextureCache.h" +#include "VertexManager.h" +#include "VertexShaderCache.h" +#include "PixelShaderCache.h" +#include "FramebufferManager.h" + +#ifdef _WIN32 + +#include "DX11/DX11_TextureCache.h" +#include "DX11/DX11_VertexShaderCache.h" +#include "DX11/DX11_PixelShaderCache.h" +#include "DX11/DX11_Render.h" +#include "DX11/DX11_VertexManager.h" + +#include "DX9/DX9_TextureCache.h" +#include "DX9/DX9_VertexShaderCache.h" +#include "DX9/DX9_PixelShaderCache.h" +#include "DX9/DX9_Render.h" +#include "DX9/DX9_VertexManager.h" + +#endif + +#include "OGL/OGL_TextureCache.h" +#include "OGL/OGL_VertexShaderCache.h" +#include "OGL/OGL_PixelShaderCache.h" +#include "OGL/OGL_Render.h" +#include "OGL/OGL_VertexManager.h" + +#include "EmuWindow.h" + +// TODO: ifdef wx this +#include "VideoConfigDiag.h" + +#include "Main.h" + +#define PLUGIN_NAME "Dolphin Video Merge [broken]" +#if defined(DEBUGFAST) +#define PLUGIN_FULL_NAME PLUGIN_NAME" (DebugFast)" +#elif defined(_DEBUG) +#define PLUGIN_FULL_NAME PLUGIN_NAME" (Debug)" +#else +#define PLUGIN_FULL_NAME PLUGIN_NAME +#endif + +HINSTANCE g_hInstance = NULL; +SVideoInitialize g_VideoInitialize; +PLUGIN_GLOBALS *g_globals = NULL; + +const char* const g_gfxapi_names[] = +{ + "Software", + "OpenGL", + "Direct3D 9", + "Direct3D 11", +}; + +#define INI_NAME "gfx_new.ini" + +// TODO: save to ini file +// TODO: move to VideoConfig or something +int g_gfxapi = 3; + +// shits +RendererBase *g_renderer; +TextureCacheBase *g_texture_cache; +VertexManagerBase *g_vertex_manager; +VertexShaderCacheBase* g_vertex_shader_cache; +PixelShaderCacheBase* g_pixel_shader_cache; +FramebufferManagerBase* g_framebuffer_manager; + +static bool s_PluginInitialized = false; +volatile u32 s_swapRequested = false; +static u32 s_efbAccessRequested = false; +static volatile u32 s_FifoShuttingDown = false; + +int frameCount; + +#if defined(HAVE_WX) && HAVE_WX +class wxDLLApp : public wxApp +{ + bool OnInit() + { + return true; + } +}; +IMPLEMENT_APP_NO_MAIN(wxDLLApp) +WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst); +#endif + +#ifdef _WIN32 +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + wxSetInstance(hinstDLL); + wxInitialize(); + break; + + case DLL_PROCESS_DETACH: + wxUninitialize(); + break; + + default: + break; + } + + g_hInstance = hinstDLL; + return true; +} +#endif + +static volatile struct +{ + u32 xfbAddr; + FieldType field; + u32 fbWidth; + u32 fbHeight; +} s_beginFieldArgs; + +static inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return !((aLower >= bUpper) || (bLower >= aUpper)); +} + +// Run from the graphics thread (from Fifo.cpp) +void VideoFifo_CheckSwapRequest() +{ + if(g_ActiveConfig.bUseXFB) + { + if (Common::AtomicLoadAcquire(s_swapRequested)) + { + EFBRectangle rc; + g_renderer->Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, + s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight, rc); + Common::AtomicStoreRelease(s_swapRequested, false); + } + } +} + +// Run from the graphics thread (from Fifo.cpp) +void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight) +{ + if (g_ActiveConfig.bUseXFB) + { + if(Common::AtomicLoadAcquire(s_swapRequested)) + { + u32 aLower = xfbAddr; + u32 aUpper = xfbAddr + 2 * fbWidth * fbHeight; + u32 bLower = s_beginFieldArgs.xfbAddr; + u32 bUpper = s_beginFieldArgs.xfbAddr + 2 * s_beginFieldArgs.fbWidth * s_beginFieldArgs.fbHeight; + + if (addrRangesOverlap(aLower, aUpper, bLower, bUpper)) + VideoFifo_CheckSwapRequest(); + } + } +} + +static struct +{ + EFBAccessType type; + u32 x; + u32 y; + u32 Data; +} s_accessEFBArgs; + +static u32 s_AccessEFBResult = 0; + +void VideoFifo_CheckEFBAccess() +{ + if (Common::AtomicLoadAcquire(s_efbAccessRequested)) + { + s_AccessEFBResult = g_renderer->AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); + + Common::AtomicStoreRelease(s_efbAccessRequested, false); + } +} + +void VideoFifo_CheckAsyncRequest() +{ + VideoFifo_CheckSwapRequest(); + VideoFifo_CheckEFBAccess(); +} + +unsigned int Callback_PeekMessages() +{ + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return 0; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 1; +} + +void UpdateFPSDisplay(const char *text) +{ + char temp[512]; + sprintf_s(temp, 512, "SVN R%s: DX11: %s", svn_rev_str, text); + SetWindowTextA(EmuWindow::GetWnd(), temp); +} + +// GLOBAL I N T E R F A C E +// ____________________________________________________________________________ +// Function: GetDllInfo +// Purpose: This function allows the emulator to gather information +// about the DLL by filling in the PluginInfo structure. +// input: A pointer to a PLUGIN_INFO structure that needs to be +// filled by the function. (see def above) +// output: none +// +void GetDllInfo(PLUGIN_INFO* _pPluginInfo) +{ + memcpy(_pPluginInfo->Name, PLUGIN_FULL_NAME, sizeof(PLUGIN_FULL_NAME)); + _pPluginInfo->Type = PLUGIN_TYPE_VIDEO; + _pPluginInfo->Version = 0x0100; +} + +// ___________________________________________________________________________ +// Function: DllConfig +// Purpose: This function is optional function that is provided +// to allow the user to configure the DLL +// input: A handle to the window that calls this function +// output: none +// +void DllConfig(void *_hParent) +{ +#if defined(HAVE_WX) && HAVE_WX + + VideoConfigDiag* const m_config_diag = new VideoConfigDiag((wxWindow *)_hParent); + m_config_diag->ShowModal(); + m_config_diag->Destroy(); + + g_Config.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str()); + + SLEEP(50); // hax to keep Dolphin window from staying hidden +#endif +} + +// ___________________________________________________________________________ +// Function: DllDebugger +// Purpose: Open the debugger +// input: a handle to the window that calls this function +// output: none +// +void* DllDebugger(void *_hParent, bool Show) +{ + // TODO: + return NULL; +} + +// ___________________________________________________________________________ +// Function: DllSetGlobals +// Purpose: Set the pointer for globals variables +// input: a pointer to the global struct +// output: none +// +void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals) +{ + g_globals = _pPluginGlobals; +} + +// ___________________________________________________________________________ +// Function: Initialize +// Purpose: Initialize the plugin +// input: Init +// output: none +// +void Initialize(void *init) +{ + frameCount = 0; + + g_VideoInitialize = *(SVideoInitialize*)init; + + InitXFBConvTables(); + + g_Config.Load((std::string(File::GetUserPath(D_CONFIG_IDX)) + INI_NAME).c_str()); + g_Config.GameIniLoad(g_globals->game_ini); + UpdateActiveConfig(); + + g_VideoInitialize.pWindowHandle = (void*)EmuWindow::Create((HWND)g_VideoInitialize.pWindowHandle, g_hInstance, _T("Loading - Please wait.")); + if (NULL == g_VideoInitialize.pWindowHandle) + { + ERROR_LOG(VIDEO, "An error has occurred while trying to create the window."); + return; + } + + g_VideoInitialize.pPeekMessages = Callback_PeekMessages; + g_VideoInitialize.pUpdateFPSDisplay = UpdateFPSDisplay; + + *(SVideoInitialize*)init = g_VideoInitialize; + + //OSD::AddMessage("Dolphin ... Video Plugin", 5000); + s_PluginInitialized = true; +} + +// ___________________________________________________________________________ +// Function: Shutdown +// Purpose: This function is called when the emulator is shutting down +// a game allowing the dll to de-initialise. +// input: none +// output: none +// +void Shutdown(void) +{ + s_efbAccessRequested = false; + s_FifoShuttingDown = false; + s_swapRequested = false; + + // VideoCommon + DLCache::Shutdown(); + CommandProcessor::Shutdown(); + PixelShaderManager::Shutdown(); + VertexShaderManager::Shutdown(); + OpcodeDecoder_Shutdown(); + VertexLoaderManager::Shutdown(); + Fifo_Shutdown(); + + // internal interfaces + EmuWindow::Close(); + + s_PluginInitialized = false; + + delete g_pixel_shader_cache; + delete g_vertex_shader_cache; + delete g_vertex_manager; + delete g_texture_cache; + delete g_renderer; +} + +// ___________________________________________________________________________ +// Function: DoState +// Purpose: Saves/load state +// input/output: ptr +// input: mode +// +void DoState(unsigned char **ptr, int mode) +{ + PanicAlert("DoState"); +} + +// ___________________________________________________________________________ +// Function: EmuStateChange +// Purpose: Notifies the plugin of a change in emulation state +// input: newState +// output: none +// +void EmuStateChange(PLUGIN_EMUSTATE newState) +{ + Fifo_RunLoop(newState == PLUGIN_EMUSTATE_PLAY); +} + +// I N T E R F A C E + + +// __________________________________________________________________________________________________ +// Function: Video_Prepare +// Purpose: This function is called from the EmuThread before the +// emulation has started. It is just for threadsensitive +// APIs like OpenGL. +// input: none +// output: none +// +void Video_Prepare(void) +{ + s_efbAccessRequested = false; + s_FifoShuttingDown = false; + s_swapRequested = false; + + switch (g_gfxapi) + { +#ifdef _WIN32 + case GFXAPI_D3D9: + g_renderer = new DX9::Renderer; + g_texture_cache = new DX9::TextureCache; + g_vertex_manager = new DX9::VertexManager; + g_vertex_shader_cache = new DX9::VertexShaderCache; + g_pixel_shader_cache = new DX9::PixelShaderCache; + break; + + case GFXAPI_D3D11: + g_renderer = new DX11::Renderer; + g_texture_cache = new DX11::TextureCache; + g_vertex_manager = new DX11::VertexManager; + g_vertex_shader_cache = new DX11::VertexShaderCache; + g_pixel_shader_cache = new DX11::PixelShaderCache; + break; +#endif + + default: + case GFXAPI_OPENGL: + g_renderer = new OGL::Renderer; + g_texture_cache = new OGL::TextureCache; + g_vertex_manager = new OGL::VertexManager; + g_vertex_shader_cache = new OGL::VertexShaderCache; + g_pixel_shader_cache = new OGL::PixelShaderCache; + break; + } + + // VideoCommon + BPInit(); + Fifo_Init(); + VertexLoaderManager::Init(); + OpcodeDecoder_Init(); + VertexShaderManager::Init(); + PixelShaderManager::Init(); + CommandProcessor::Init(); + PixelEngine::Init(); + DLCache::Init(); + + // tell the host that the window is ready + g_VideoInitialize.pCoreMessage(WM_USER_CREATE); +} + +// __________________________________________________________________________________________________ +// Function: Video_BeginField +// Purpose: When a field begins in the VI emulator, this function tells the video plugin what the +// parameters of the upcoming field are. The video plugin should make sure the previous +// field is on the player's display before returning. +// input: vi parameters of the upcoming field +// output: none +// +void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) +{ + if (s_PluginInitialized && g_ActiveConfig.bUseXFB) + { + if (g_VideoInitialize.bOnThread) + { + while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown) + //Common::SleepCurrentThread(1); + Common::YieldCPU(); + } + else + VideoFifo_CheckSwapRequest(); + s_beginFieldArgs.xfbAddr = xfbAddr; + s_beginFieldArgs.field = field; + s_beginFieldArgs.fbWidth = fbWidth; + s_beginFieldArgs.fbHeight = fbHeight; + + Common::AtomicStoreRelease(s_swapRequested, true); + } +} + +// __________________________________________________________________________________________________ +// Function: Video_EndField +// Purpose: When a field ends in the VI emulator, this function notifies the video plugin. The video +// has permission to swap the field to the player's display. +// input: none +// output: none +// +void Video_EndField() +{ + return; +} + +// __________________________________________________________________________________________________ +// Function: Video_AccessEFB +// input: type of access (r/w, z/color, ...), x coord, y coord +// output: response to the access request (ex: peek z data at specified coord) +// +u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) +{ + if (s_PluginInitialized) + { + s_accessEFBArgs.type = type; + s_accessEFBArgs.x = x; + s_accessEFBArgs.y = y; + s_accessEFBArgs.Data = InputData; + Common::AtomicStoreRelease(s_efbAccessRequested, true); + + if (g_VideoInitialize.bOnThread) + { + while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) + //Common::SleepCurrentThread(1); + Common::YieldCPU(); + } + else + VideoFifo_CheckEFBAccess(); + + return s_AccessEFBResult; + } + return 0; +} + +// __________________________________________________________________________________________________ +// Function: Video_Screenshot +// input: Filename +// output: true if all was okay +// +void Video_Screenshot(const char *_szFilename) +{ + PanicAlert("Screenshots are not yet supported."); + return; +} + +// __________________________________________________________________________________________________ +// Function: Video_EnterLoop +// Purpose: Enters the video fifo dispatch loop. This is only used in Dual Core mode. +// input: none +// output: none +// +void Video_EnterLoop() +{ + Fifo_EnterLoop(g_VideoInitialize); +} + +// __________________________________________________________________________________________________ +// Function: Video_ExitLoop +// Purpose: Exits the video dispatch loop. This is only used in Dual Core mode. +// input: none +// output: none +// +void Video_ExitLoop() +{ + Fifo_ExitLoop(); + s_FifoShuttingDown = true; +} + +// __________________________________________________________________________________________________ +// Function: Video_SetRendering +// Purpose: Sets video rendering on and off. Currently used for frame skipping +// input: Enabled toggle +// output: none +// +void Video_SetRendering(bool bEnabled) +{ + PanicAlert("SetRendering is not yet supported."); +} + +// __________________________________________________________________________________________________ +// Function: Video_AddMessage +// Purpose: Adds a message to the display queue, to be shown forthe specified time +// input: pointer to the null-terminated string, time in milliseconds +// output: none +// +void Video_AddMessage(const char* pstr, unsigned int milliseconds) +{ + return; +} + +void Video_CommandProcessorRead16(u16& _rReturnValue, const u32 _Address) +{ + CommandProcessor::Read16(_rReturnValue, _Address); +} + +void Video_CommandProcessorWrite16(const u16 _Data, const u32 _Address) +{ + CommandProcessor::Write16(_Data, _Address); +} + +void Video_PixelEngineRead16(u16& _rReturnValue, const u32 _Address) +{ + PixelEngine::Read16(_rReturnValue, _Address); +} + +void Video_PixelEngineWrite16(const u16 _Data, const u32 _Address) +{ + PixelEngine::Write16(_Data, _Address); +} + +void Video_PixelEngineWrite32(const u32 _Data, const u32 _Address) +{ + PixelEngine::Write32(_Data, _Address); +} + +void Video_GatherPipeBursted(void) +{ + CommandProcessor::GatherPipeBursted(); +} + +void Video_WaitForFrameFinish(void) +{ + CommandProcessor::WaitForFrameFinish(); +} + +// __________________________________________________________________________________________________ +// Function: Video_IsFifoBusy +// Purpose: Return if the FIFO is proecessing data, that is used for sync gfx thread and emulator +// thread in CoreTiming +// input: none +// output: bool +// +bool Video_IsFifoBusy(void) +{ + return CommandProcessor::isFifoBusy; +} + +void Video_AbortFrame(void) +{ + CommandProcessor::AbortFrame(); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/Main.h b/Source/Plugins/Plugin_VideoMerge/Src/Main.h index d869cedf0a..ff451bdd9a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/Main.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/Main.h @@ -1,57 +1,57 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -#include "PluginSpecs_Video.h" - -#include "Renderer.h" -#include "TextureCache.h" -#include "VertexManager.h" -#include "PixelShaderCache.h" -#include "VertexShaderCache.h" -#include "FramebufferManager.h" - -extern SVideoInitialize g_VideoInitialize; -extern volatile u32 s_swapRequested; -extern PLUGIN_GLOBALS *g_globals; - -extern RendererBase *g_renderer; -extern TextureCacheBase *g_texture_cache; -extern VertexManagerBase *g_vertex_manager; -extern VertexShaderCacheBase* g_vertex_shader_cache; -extern PixelShaderCacheBase* g_pixel_shader_cache; -extern FramebufferManagerBase* g_framebuffer_manager; - -extern int frameCount; - -void VideoFifo_CheckEFBAccess(); -void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight); - -enum -{ - GFXAPI_SOFTWARE, - GFXAPI_OPENGL, - GFXAPI_D3D9, - GFXAPI_D3D11, -}; - -extern const char* const g_gfxapi_names[]; -extern int g_gfxapi; - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "PluginSpecs_Video.h" + +#include "Renderer.h" +#include "TextureCache.h" +#include "VertexManager.h" +#include "PixelShaderCache.h" +#include "VertexShaderCache.h" +#include "FramebufferManager.h" + +extern SVideoInitialize g_VideoInitialize; +extern volatile u32 s_swapRequested; +extern PLUGIN_GLOBALS *g_globals; + +extern RendererBase *g_renderer; +extern TextureCacheBase *g_texture_cache; +extern VertexManagerBase *g_vertex_manager; +extern VertexShaderCacheBase* g_vertex_shader_cache; +extern PixelShaderCacheBase* g_pixel_shader_cache; +extern FramebufferManagerBase* g_framebuffer_manager; + +extern int frameCount; + +void VideoFifo_CheckEFBAccess(); +void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight); + +enum +{ + GFXAPI_SOFTWARE, + GFXAPI_OPENGL, + GFXAPI_D3D9, + GFXAPI_D3D11, +}; + +extern const char* const g_gfxapi_names[]; +extern int g_gfxapi; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.cpp index f03edef9f7..9cbdf59eae 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.cpp @@ -1,385 +1,385 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// OGL -#include "OGL_Render.h" -#include "OGL_XFB.h" -#include "OGL_FramebufferManager.h" -#include "OGL_TextureConverter.h" - -namespace OGL -{ - -extern bool s_bHaveFramebufferBlit; // comes from Render.cpp - -int FramebufferManager::m_targetWidth; -int FramebufferManager::m_targetHeight; -int FramebufferManager::m_msaaSamples; -int FramebufferManager::m_msaaCoverageSamples; - -GLuint FramebufferManager::m_efbFramebuffer; -GLuint FramebufferManager::m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise -GLuint FramebufferManager::m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise - -// Only used in MSAA mode. -GLuint FramebufferManager::m_resolvedFramebuffer; -GLuint FramebufferManager::m_resolvedColorTexture; -GLuint FramebufferManager::m_resolvedDepthTexture; - -GLuint FramebufferManager::m_xfbFramebuffer; // Only used in MSAA mode -XFBSource FramebufferManager::m_realXFBSource; // Only used in Real XFB mode - -FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) -{ - // m_efbFramebuffer(0), - // m_efbColor(0), - // m_efbDepth(0), - // m_resolvedFramebuffer(0), - // m_resolvedColorTexture(0), - // m_resolvedDepthTexture(0), - // m_xfbFramebuffer(0) - - m_targetWidth = targetWidth; - m_targetHeight = targetHeight; - m_msaaSamples = msaaSamples; - m_msaaCoverageSamples = msaaCoverageSamples; - - // The EFB can be set to different pixel formats by the game through the - // BPMEM_ZCOMPARE register (which should probably have a different name). - // They are: - // - 24-bit RGB (8-bit components) with 24-bit Z - // - 24-bit RGBA (6-bit components) with 24-bit Z - // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z - // We only use one EFB format here: 32-bit ARGB with 24-bit Z. - // Multisampling depends on user settings. - // The distinction becomes important for certain operations, i.e. the - // alpha channel should be ignored if the EFB does not have one. - - // Create EFB target. - - glGenFramebuffersEXT(1, &m_efbFramebuffer); - - if (m_msaaSamples <= 1) - { - // EFB targets will be textures in non-MSAA mode. - - GLuint glObj[2]; - glGenTextures(2, glObj); - m_efbColor = glObj[0]; - m_efbDepth = glObj[1]; - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Bind target textures to the EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0); - - GL_REPORT_FBO_ERROR(); - } - else - { - // EFB targets will be renderbuffers in MSAA mode (required by OpenGL). - // Resolve targets will be created to transfer EFB to RAM textures. - // XFB framebuffer will be created to transfer EFB to XFB texture. - - // Create EFB target renderbuffers. - - GLuint glObj[2]; - glGenRenderbuffersEXT(2, glObj); - m_efbColor = glObj[0]; - m_efbDepth = glObj[1]; - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor); - if (m_msaaCoverageSamples) - glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); - else - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth); - if (m_msaaCoverageSamples) - glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); - else - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); - - // Bind target renderbuffers to EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth); - - GL_REPORT_FBO_ERROR(); - - // Create resolved targets for transferring multisampled EFB to texture. - - glGenFramebuffersEXT(1, &m_resolvedFramebuffer); - - glGenTextures(2, glObj); - m_resolvedColorTexture = glObj[0]; - m_resolvedDepthTexture = glObj[1]; - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Bind resolved textures to resolved framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0); - - GL_REPORT_FBO_ERROR(); - - // Return to EFB framebuffer. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - } - - // Create XFB framebuffer; targets will be created elsewhere. - - glGenFramebuffersEXT(1, &m_xfbFramebuffer); - - // EFB framebuffer is currently bound. -} - -FramebufferManager::~FramebufferManager() -{ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - GLuint glObj[3]; - - // Note: OpenGL deletion functions silently ignore parameters of "0". - - glObj[0] = m_efbFramebuffer; - glObj[1] = m_resolvedFramebuffer; - glObj[2] = m_xfbFramebuffer; - glDeleteFramebuffersEXT(3, glObj); - m_efbFramebuffer = 0; - m_xfbFramebuffer = 0; - - glObj[0] = m_resolvedColorTexture; - glObj[1] = m_resolvedDepthTexture; - glObj[2] = m_realXFBSource.texture; - glDeleteTextures(3, glObj); - m_resolvedColorTexture = 0; - m_resolvedDepthTexture = 0; - m_realXFBSource.texture = 0; - - glObj[0] = m_efbColor; - glObj[1] = m_efbDepth; - if (m_msaaSamples <= 1) - glDeleteTextures(2, glObj); - else - glDeleteRenderbuffersEXT(2, glObj); - m_efbColor = 0; - m_efbDepth = 0; -} - -XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) -{ - XFBSource* const xfbs = new XFBSource; - - glGenTextures(1, &xfbs->texture); - - return xfbs; -} - -void XFBSource::CopyEFB(const TargetRectangle& efbSource) -{ - // Copy EFB to XFB texture - -#if 0 - if (m_msaaSamples <= 1) -#else - if (!s_bHaveFramebufferBlit) -#endif - { - // Just copy the EFB directly. - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); - glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, texWidth, texHeight, 0); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - else - { - // OpenGL cannot copy directly from a multisampled framebuffer, so use - // EXT_framebuffer_blit. - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, FramebufferManager::m_xfbFramebuffer); - - // Bind texture. - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, texture, 0); - - GL_REPORT_FBO_ERROR(); - - glBlitFramebufferEXT(0, 0, texWidth, texHeight, 0, 0, texWidth, - texHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - // Unbind texture. - glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); - } -} - -GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) -{ - if (m_msaaSamples <= 1) - { - return m_efbColor; - } - else - { - // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is - // required. - - TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(sourceRc); - targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); - - // Resolve. - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - glBlitFramebufferEXT( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_COLOR_BUFFER_BIT, GL_NEAREST - ); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - return m_resolvedColorTexture; - } -} - -GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) -{ - if (m_msaaSamples <= 1) - { - return m_efbDepth; - } - else - { - // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is - // required. - - TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(sourceRc); - targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); - - // Resolve. - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); - glBlitFramebufferEXT( - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, - GL_DEPTH_BUFFER_BIT, GL_NEAREST - ); - - // Return to EFB. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); - - return m_resolvedDepthTexture; - } -} - -void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - u8* pXFB = Memory_GetPtr(xfbAddr); - if (!pXFB) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } - - XFB_Write(pXFB, sourceRc, fbWidth, fbHeight); -} - -const XFBSourceBase** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) -{ - xfbCount = 1; - - m_realXFBSource.texWidth = MAX_XFB_WIDTH; - m_realXFBSource.texHeight = MAX_XFB_HEIGHT; - - m_realXFBSource.srcAddr = xfbAddr; - m_realXFBSource.srcWidth = fbWidth; - m_realXFBSource.srcHeight = fbHeight; - - // OpenGL texture coordinates originate at the lower left, which is why - // sourceRc.top = fbHeight and sourceRc.bottom = 0. - m_realXFBSource.sourceRc.left = 0; - m_realXFBSource.sourceRc.top = fbHeight; - m_realXFBSource.sourceRc.right = fbWidth; - m_realXFBSource.sourceRc.bottom = 0; - - if (!m_realXFBSource.texture) - { - glGenTextures(1, &m_realXFBSource.texture); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - } - - // Decode YUYV data from GameCube RAM - TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); - - m_overlappingXFBArray[0] = &m_realXFBSource; - - return &m_overlappingXFBArray[0]; -} - -void FramebufferManager::SetFramebuffer(GLuint fb) -{ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : GetEFBFramebuffer()); -} - -// Apply AA if enabled -GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle &source_rect) -{ - return GetEFBColorTexture(source_rect); -} - -GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_rect) -{ - return GetEFBDepthTexture(source_rect); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// OGL +#include "OGL_Render.h" +#include "OGL_XFB.h" +#include "OGL_FramebufferManager.h" +#include "OGL_TextureConverter.h" + +namespace OGL +{ + +extern bool s_bHaveFramebufferBlit; // comes from Render.cpp + +int FramebufferManager::m_targetWidth; +int FramebufferManager::m_targetHeight; +int FramebufferManager::m_msaaSamples; +int FramebufferManager::m_msaaCoverageSamples; + +GLuint FramebufferManager::m_efbFramebuffer; +GLuint FramebufferManager::m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise +GLuint FramebufferManager::m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise + +// Only used in MSAA mode. +GLuint FramebufferManager::m_resolvedFramebuffer; +GLuint FramebufferManager::m_resolvedColorTexture; +GLuint FramebufferManager::m_resolvedDepthTexture; + +GLuint FramebufferManager::m_xfbFramebuffer; // Only used in MSAA mode +XFBSource FramebufferManager::m_realXFBSource; // Only used in Real XFB mode + +FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples) +{ + // m_efbFramebuffer(0), + // m_efbColor(0), + // m_efbDepth(0), + // m_resolvedFramebuffer(0), + // m_resolvedColorTexture(0), + // m_resolvedDepthTexture(0), + // m_xfbFramebuffer(0) + + m_targetWidth = targetWidth; + m_targetHeight = targetHeight; + m_msaaSamples = msaaSamples; + m_msaaCoverageSamples = msaaCoverageSamples; + + // The EFB can be set to different pixel formats by the game through the + // BPMEM_ZCOMPARE register (which should probably have a different name). + // They are: + // - 24-bit RGB (8-bit components) with 24-bit Z + // - 24-bit RGBA (6-bit components) with 24-bit Z + // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z + // We only use one EFB format here: 32-bit ARGB with 24-bit Z. + // Multisampling depends on user settings. + // The distinction becomes important for certain operations, i.e. the + // alpha channel should be ignored if the EFB does not have one. + + // Create EFB target. + + glGenFramebuffersEXT(1, &m_efbFramebuffer); + + if (m_msaaSamples <= 1) + { + // EFB targets will be textures in non-MSAA mode. + + GLuint glObj[2]; + glGenTextures(2, glObj); + m_efbColor = glObj[0]; + m_efbDepth = glObj[1]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + // Bind target textures to the EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0); + + GL_REPORT_FBO_ERROR(); + } + else + { + // EFB targets will be renderbuffers in MSAA mode (required by OpenGL). + // Resolve targets will be created to transfer EFB to RAM textures. + // XFB framebuffer will be created to transfer EFB to XFB texture. + + // Create EFB target renderbuffers. + + GLuint glObj[2]; + glGenRenderbuffersEXT(2, glObj); + m_efbColor = glObj[0]; + m_efbDepth = glObj[1]; + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor); + if (m_msaaCoverageSamples) + glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); + else + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth); + if (m_msaaCoverageSamples) + glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); + else + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + // Bind target renderbuffers to EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth); + + GL_REPORT_FBO_ERROR(); + + // Create resolved targets for transferring multisampled EFB to texture. + + glGenFramebuffersEXT(1, &m_resolvedFramebuffer); + + glGenTextures(2, glObj); + m_resolvedColorTexture = glObj[0]; + m_resolvedDepthTexture = glObj[1]; + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + + // Bind resolved textures to resolved framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0); + + GL_REPORT_FBO_ERROR(); + + // Return to EFB framebuffer. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + } + + // Create XFB framebuffer; targets will be created elsewhere. + + glGenFramebuffersEXT(1, &m_xfbFramebuffer); + + // EFB framebuffer is currently bound. +} + +FramebufferManager::~FramebufferManager() +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + GLuint glObj[3]; + + // Note: OpenGL deletion functions silently ignore parameters of "0". + + glObj[0] = m_efbFramebuffer; + glObj[1] = m_resolvedFramebuffer; + glObj[2] = m_xfbFramebuffer; + glDeleteFramebuffersEXT(3, glObj); + m_efbFramebuffer = 0; + m_xfbFramebuffer = 0; + + glObj[0] = m_resolvedColorTexture; + glObj[1] = m_resolvedDepthTexture; + glObj[2] = m_realXFBSource.texture; + glDeleteTextures(3, glObj); + m_resolvedColorTexture = 0; + m_resolvedDepthTexture = 0; + m_realXFBSource.texture = 0; + + glObj[0] = m_efbColor; + glObj[1] = m_efbDepth; + if (m_msaaSamples <= 1) + glDeleteTextures(2, glObj); + else + glDeleteRenderbuffersEXT(2, glObj); + m_efbColor = 0; + m_efbDepth = 0; +} + +XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height) +{ + XFBSource* const xfbs = new XFBSource; + + glGenTextures(1, &xfbs->texture); + + return xfbs; +} + +void XFBSource::CopyEFB(const TargetRectangle& efbSource) +{ + // Copy EFB to XFB texture + +#if 0 + if (m_msaaSamples <= 1) +#else + if (!s_bHaveFramebufferBlit) +#endif + { + // Just copy the EFB directly. + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, texWidth, texHeight, 0); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + else + { + // OpenGL cannot copy directly from a multisampled framebuffer, so use + // EXT_framebuffer_blit. + + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, FramebufferManager::m_xfbFramebuffer); + + // Bind texture. + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, texture, 0); + + GL_REPORT_FBO_ERROR(); + + glBlitFramebufferEXT(0, 0, texWidth, texHeight, 0, 0, texWidth, + texHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Unbind texture. + glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::m_efbFramebuffer); + } +} + +GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) +{ + if (m_msaaSamples <= 1) + { + return m_efbColor; + } + else + { + // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is + // required. + + TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(sourceRc); + targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); + + // Resolve. + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + glBlitFramebufferEXT( + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + return m_resolvedColorTexture; + } +} + +GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& sourceRc) +{ + if (m_msaaSamples <= 1) + { + return m_efbDepth; + } + else + { + // Transfer the EFB to a resolved texture. EXT_framebuffer_blit is + // required. + + TargetRectangle targetRc = RendererBase::ConvertEFBRectangle(sourceRc); + targetRc.ClampLL(0, 0, m_targetWidth, m_targetHeight); + + // Resolve. + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer); + glBlitFramebufferEXT( + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + targetRc.left, targetRc.top, targetRc.right, targetRc.bottom, + GL_DEPTH_BUFFER_BIT, GL_NEAREST + ); + + // Return to EFB. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer); + + return m_resolvedDepthTexture; + } +} + +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + u8* pXFB = Memory_GetPtr(xfbAddr); + if (!pXFB) + { + WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + return; + } + + XFB_Write(pXFB, sourceRc, fbWidth, fbHeight); +} + +const XFBSourceBase** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + xfbCount = 1; + + m_realXFBSource.texWidth = MAX_XFB_WIDTH; + m_realXFBSource.texHeight = MAX_XFB_HEIGHT; + + m_realXFBSource.srcAddr = xfbAddr; + m_realXFBSource.srcWidth = fbWidth; + m_realXFBSource.srcHeight = fbHeight; + + // OpenGL texture coordinates originate at the lower left, which is why + // sourceRc.top = fbHeight and sourceRc.bottom = 0. + m_realXFBSource.sourceRc.left = 0; + m_realXFBSource.sourceRc.top = fbHeight; + m_realXFBSource.sourceRc.right = fbWidth; + m_realXFBSource.sourceRc.bottom = 0; + + if (!m_realXFBSource.texture) + { + glGenTextures(1, &m_realXFBSource.texture); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + } + + // Decode YUYV data from GameCube RAM + TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); + + m_overlappingXFBArray[0] = &m_realXFBSource; + + return &m_overlappingXFBArray[0]; +} + +void FramebufferManager::SetFramebuffer(GLuint fb) +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : GetEFBFramebuffer()); +} + +// Apply AA if enabled +GLuint FramebufferManager::ResolveAndGetRenderTarget(const EFBRectangle &source_rect) +{ + return GetEFBColorTexture(source_rect); +} + +GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_rect) +{ + return GetEFBDepthTexture(source_rect); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.h index 70571d4f25..82551dc123 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_FramebufferManager.h @@ -1,135 +1,135 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_FRAMEBUFFERMANAGER_H_ -#define _OGL_FRAMEBUFFERMANAGER_H_ - -#include - -#include "OGL_GLUtil.h" - -#include "../FramebufferManager.h" - -namespace OGL -{ - -// On the GameCube, the game sends a request for the graphics processor to -// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM -// called the XFB (External Framebuffer). The size and location of the XFB is -// decided at the time of the copy, and the format is always YUYV. The video -// interface is given a pointer to the XFB, which will be decoded and -// displayed on the TV. -// -// There are two ways for Dolphin to emulate this: -// -// Real XFB mode: -// -// Dolphin will behave like the GameCube and encode the EFB to -// a portion of GameCube RAM. The emulated video interface will decode the data -// for output to the screen. -// -// Advantages: Behaves exactly like the GameCube. -// Disadvantages: Resolution will be limited. -// -// Virtual XFB mode: -// -// When a request is made to copy the EFB to an XFB, Dolphin -// will remember the RAM location and size of the XFB in a Virtual XFB list. -// The video interface will look up the XFB in the list and use the enhanced -// data stored there, if available. -// -// Advantages: Enables high resolution graphics, better than real hardware. -// Disadvantages: If the GameCube CPU writes directly to the XFB (which is -// possible but uncommon), the Virtual XFB will not capture this information. - -// There may be multiple XFBs in GameCube RAM. This is the maximum number to -// virtualize. - -inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) -{ - return !((aLower >= bUpper) || (bLower >= aUpper)); -} - -struct XFBSource : XFBSourceBase -{ - XFBSource() : texture(0) {} - - void CopyEFB(const TargetRectangle& efbSource); - - GLuint texture; - TargetRectangle sourceRc; -}; - -class FramebufferManager : public ::FramebufferManagerBase -{ - friend struct XFBSource; - -public: - FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples); - ~FramebufferManager(); - - // To get the EFB in texture form, these functions may have to transfer - // the EFB to a resolved texture first. - static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc); - static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc); - - static GLuint GetEFBFramebuffer() { return m_efbFramebuffer; } - - // Resolved framebuffer is only used in MSAA mode. - static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer; } - - static void SetFramebuffer(GLuint fb); - - // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. - // Thus, this call may be expensive. Don't repeat it unnecessarily. - // If not in MSAA mode, will just return the render target texture ID. - // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect); - - // Same as above but for the depth Target. - // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. - static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect); - - XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height); - -protected: - static GLuint m_efbFramebuffer; - static GLuint m_xfbFramebuffer; // Only used in MSAA mode - -private: - static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - static const XFBSourceBase** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); - - static int m_targetWidth; - static int m_targetHeight; - static int m_msaaSamples; - static int m_msaaCoverageSamples; - - static GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise - static GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise - - // Only used in MSAA mode. - static GLuint m_resolvedFramebuffer; - static GLuint m_resolvedColorTexture; - static GLuint m_resolvedDepthTexture; - - static XFBSource m_realXFBSource; // Only used in Real XFB mode -}; - -} - -#endif +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_FRAMEBUFFERMANAGER_H_ +#define _OGL_FRAMEBUFFERMANAGER_H_ + +#include + +#include "OGL_GLUtil.h" + +#include "../FramebufferManager.h" + +namespace OGL +{ + +// On the GameCube, the game sends a request for the graphics processor to +// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM +// called the XFB (External Framebuffer). The size and location of the XFB is +// decided at the time of the copy, and the format is always YUYV. The video +// interface is given a pointer to the XFB, which will be decoded and +// displayed on the TV. +// +// There are two ways for Dolphin to emulate this: +// +// Real XFB mode: +// +// Dolphin will behave like the GameCube and encode the EFB to +// a portion of GameCube RAM. The emulated video interface will decode the data +// for output to the screen. +// +// Advantages: Behaves exactly like the GameCube. +// Disadvantages: Resolution will be limited. +// +// Virtual XFB mode: +// +// When a request is made to copy the EFB to an XFB, Dolphin +// will remember the RAM location and size of the XFB in a Virtual XFB list. +// The video interface will look up the XFB in the list and use the enhanced +// data stored there, if available. +// +// Advantages: Enables high resolution graphics, better than real hardware. +// Disadvantages: If the GameCube CPU writes directly to the XFB (which is +// possible but uncommon), the Virtual XFB will not capture this information. + +// There may be multiple XFBs in GameCube RAM. This is the maximum number to +// virtualize. + +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return !((aLower >= bUpper) || (bLower >= aUpper)); +} + +struct XFBSource : XFBSourceBase +{ + XFBSource() : texture(0) {} + + void CopyEFB(const TargetRectangle& efbSource); + + GLuint texture; + TargetRectangle sourceRc; +}; + +class FramebufferManager : public ::FramebufferManagerBase +{ + friend struct XFBSource; + +public: + FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples); + ~FramebufferManager(); + + // To get the EFB in texture form, these functions may have to transfer + // the EFB to a resolved texture first. + static GLuint GetEFBColorTexture(const EFBRectangle& sourceRc); + static GLuint GetEFBDepthTexture(const EFBRectangle& sourceRc); + + static GLuint GetEFBFramebuffer() { return m_efbFramebuffer; } + + // Resolved framebuffer is only used in MSAA mode. + static GLuint GetResolvedFramebuffer() { return m_resolvedFramebuffer; } + + static void SetFramebuffer(GLuint fb); + + // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. + // Thus, this call may be expensive. Don't repeat it unnecessarily. + // If not in MSAA mode, will just return the render target texture ID. + // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. + static GLuint ResolveAndGetRenderTarget(const EFBRectangle &rect); + + // Same as above but for the depth Target. + // After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. + static GLuint ResolveAndGetDepthTarget(const EFBRectangle &rect); + + XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height); + +protected: + static GLuint m_efbFramebuffer; + static GLuint m_xfbFramebuffer; // Only used in MSAA mode + +private: + static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + static const XFBSourceBase** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + + static int m_targetWidth; + static int m_targetHeight; + static int m_msaaSamples; + static int m_msaaCoverageSamples; + + static GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise + static GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise + + // Only used in MSAA mode. + static GLuint m_resolvedFramebuffer; + static GLuint m_resolvedColorTexture; + static GLuint m_resolvedDepthTexture; + + static XFBSource m_realXFBSource; // Only used in Real XFB mode +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.cpp index 8664443fb1..02380a7f0e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.cpp @@ -1,514 +1,514 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "IniFile.h" -#include "Setup.h" - -// VideoCommon -#include "VideoConfig.h" - -// OGL -#include "OGL_Render.h" -#include "OGL_GLUtil.h" - -#ifdef _WIN32 -#include "../EmuWindow.h" -extern HINSTANCE g_hInstance; -#endif - -namespace OGL -{ - -#ifdef _WIN32 -static HDC hDC = NULL; // Private GDI Device Context -static HGLRC hRC = NULL; // Permanent Rendering Context -#else -GLWindow GLWin; -#endif - -// Handles OpenGL and the window - -// Window dimensions. -static int s_backbuffer_width; -static int s_backbuffer_height; - -void OpenGL_SwapBuffers() -{ -#if defined(USE_WX) && USE_WX - GLWin.glCanvas->SwapBuffers(); -#elif defined(__APPLE__) - cocoaGLSwap(GLWin.cocoaCtx,GLWin.cocoaWin); -#elif defined(_WIN32) - SwapBuffers(hDC); -#elif defined(HAVE_X11) && HAVE_X11 - glXSwapBuffers(GLWin.dpy, GLWin.win); -#endif -} - -u32 OpenGL_GetBackbufferWidth() -{ - return s_backbuffer_width; -} - -u32 OpenGL_GetBackbufferHeight() -{ - return s_backbuffer_height; -} - -void OpenGL_SetWindowText(const char *text) -{ -#if defined(USE_WX) && USE_WX - // GLWin.frame->SetTitle(wxString::FromAscii(text)); -#elif defined(__APPLE__) - cocoaGLSetTitle(GLWin.cocoaWin, text); -#elif defined(_WIN32) - // TODO convert text to unicode and change SetWindowTextA to SetWindowText - SetWindowTextA(EmuWindow::GetWnd(), text); -#elif defined(HAVE_X11) && HAVE_X11 - // Tell X to ask the window manager to set the window title. - // (X itself doesn't provide window title functionality.) - XStoreName(GLWin.dpy, GLWin.win, text); -#endif -} - -#if defined(HAVE_X11) && HAVE_X11 -THREAD_RETURN XEventThread(void *pArg); - -void CreateXWindow (void) -{ - Atom wmProtocols[1]; - - // Setup window attributes - GLWin.attr.colormap = XCreateColormap(GLWin.dpy, - GLWin.parent, GLWin.vi->visual, AllocNone); - GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask; - GLWin.attr.background_pixel = BlackPixel(GLWin.dpy, GLWin.screen); - GLWin.attr.border_pixel = 0; - - // Create the window - GLWin.win = XCreateWindow(GLWin.dpy, GLWin.parent, - GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual, - CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr); - wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); - XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 1); - XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL); - XMapRaised(GLWin.dpy, GLWin.win); - XSync(GLWin.dpy, True); - - GLWin.xEventThread = new Common::Thread(XEventThread, NULL); -} - -void DestroyXWindow(void) -{ - XUnmapWindow(GLWin.dpy, GLWin.win); - GLWin.win = 0; - XFreeColormap(GLWin.dpy, GLWin.attr.colormap); - if (GLWin.xEventThread) - GLWin.xEventThread->WaitForDeath(); - GLWin.xEventThread = NULL; -} - -THREAD_RETURN XEventThread(void *pArg) -{ - while (GLWin.win) - { - XEvent event; - KeySym key; - for (int num_events = XPending(GLWin.dpy); num_events > 0; num_events--) { - XNextEvent(GLWin.dpy, &event); - switch(event.type) { - case KeyPress: - key = XLookupKeysym((XKeyEvent*)&event, 0); - switch (key) - { - case XK_3: - OSDChoice = 1; - // Toggle native resolution - if (!(g_Config.bNativeResolution || g_Config.b2xResolution)) - g_Config.bNativeResolution = true; - else if (g_Config.bNativeResolution && Renderer::AllowCustom()) - { - g_Config.bNativeResolution = false; - if (Renderer::Allow2x()) - g_Config.b2xResolution = true; - } - else if (Renderer::AllowCustom()) - g_Config.b2xResolution = false; - break; - case XK_4: - OSDChoice = 2; - // Toggle aspect ratio - g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; - break; - case XK_5: - OSDChoice = 3; - // Toggle EFB copy - if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture) - { - g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable; - g_Config.bCopyEFBToTexture = false; - } - else - { - g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; - } - break; - case XK_6: - OSDChoice = 4; - g_Config.bDisableFog = !g_Config.bDisableFog; - break; - case XK_7: - OSDChoice = 5; - g_Config.bDisableLighting = !g_Config.bDisableLighting; - break; - default: - break; - } - break; - case ConfigureNotify: - Window winDummy; - unsigned int borderDummy, depthDummy; - XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, - &GLWin.width, &GLWin.height, &borderDummy, &depthDummy); - s_backbuffer_width = GLWin.width; - s_backbuffer_height = GLWin.height; - break; - case ClientMessage: - if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False)) - g_VideoInitialize.pCoreMessage(WM_USER_STOP); - if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESIZE", False)) - XMoveResizeWindow(GLWin.dpy, GLWin.win, event.xclient.data.l[1], - event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]); - break; - default: - break; - } - } - Common::SleepCurrentThread(20); - } - return 0; -} -#endif - -// Create rendering window. -// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight) -{ - int _tx, _ty, _twidth, _theight; - g_VideoInitialize.pRequestWindowSize(_tx, _ty, _twidth, _theight); - - // Control window size and picture scaling - s_backbuffer_width = _twidth; - s_backbuffer_height = _theight; - -#if defined(USE_WX) && USE_WX - int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0}; - - wxSize size(_twidth, _theight); - - GLWin.panel = (wxPanel *)g_VideoInitialize.pWindowHandle; - - GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, args, - wxPoint(0,0), size, wxSUNKEN_BORDER); - GLWin.glCtxt = new wxGLContext(GLWin.glCanvas); - GLWin.glCanvas->Show(TRUE); - - GLWin.glCanvas->SetCurrent(*GLWin.glCtxt); - -#elif defined(__APPLE__) - GLWin.width = s_backbuffer_width; - GLWin.height = s_backbuffer_height; - GLWin.cocoaWin = cocoaGLCreateWindow(GLWin.width, GLWin.height); - GLWin.cocoaCtx = cocoaGLInit(g_Config.iMultisampleMode); - -#elif defined(_WIN32) - - PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be - { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - 32, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // 8bit Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 24, // 24Bit Z-Buffer (Depth Buffer) - 8, // 8bit Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - GLuint PixelFormat; // Holds The Results After Searching For A Match - - if (!(hDC=GetDC(EmuWindow::GetWnd()))) { - PanicAlert("(1) Can't create an OpenGL Device context. Fail."); - return false; - } - if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) { - PanicAlert("(2) Can't find a suitable PixelFormat."); - return false; - } - if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { - PanicAlert("(3) Can't set the PixelFormat."); - return false; - } - if (!(hRC = wglCreateContext(hDC))) { - PanicAlert("(4) Can't create an OpenGL rendering context."); - return false; - } - // -------------------------------------- - -#elif defined(HAVE_X11) && HAVE_X11 - int glxMajorVersion, glxMinorVersion; - - // attributes for a single buffered visual in RGBA format with at least - // 8 bits per color and a 24 bit depth buffer - int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None}; - - // attributes for a double buffered visual in RGBA format with at least - // 8 bits per color and a 24 bit depth buffer - int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, - GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, - None }; - - int attrListDefault[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, - None }; - - GLWin.dpy = XOpenDisplay(0); - GLWin.parent = (Window)g_VideoInitialize.pWindowHandle; - GLWin.screen = DefaultScreen(GLWin.dpy); - if (GLWin.parent == 0) - GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen); - - glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); - NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion); - - // Get an appropriate visual - GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); - if (GLWin.vi == NULL) - { - GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); - if (GLWin.vi != NULL) - { - ERROR_LOG(VIDEO, "Only Singlebuffered Visual!"); - } - else - { - GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault); - if (GLWin.vi == NULL) - { - ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)"); - exit(0); - } - } - } - else - NOTICE_LOG(VIDEO, "Got Doublebuffered Visual!"); - - // Create a GLX context. - GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE); - if (!GLWin.ctx) - { - PanicAlert("Couldn't Create GLX context.Quit"); - exit(0); // TODO: Don't bring down entire Emu - } - - GLWin.x = _tx; - GLWin.y = _ty; - GLWin.width = _twidth; - GLWin.height = _theight; - - CreateXWindow(); - g_VideoInitialize.pWindowHandle = (void *)GLWin.win; -#endif - return true; -} - -bool OpenGL_MakeCurrent() -{ - // connect the glx-context to the window -#if defined(USE_WX) && USE_WX - GLWin.glCanvas->SetCurrent(*GLWin.glCtxt); -#elif defined(__APPLE__) - cocoaGLMakeCurrent(GLWin.cocoaCtx,GLWin.cocoaWin); -#elif defined(_WIN32) - return wglMakeCurrent(hDC,hRC) ? true : false; -#elif defined(HAVE_X11) && HAVE_X11 -#if defined(HAVE_WX) && (HAVE_WX) - g_VideoInitialize.pRequestWindowSize(GLWin.x, GLWin.y, (int&)GLWin.width, (int&)GLWin.height); - XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height); -#endif - return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); -#endif - return true; -} - -// Update window width, size and etc. Called from Render.cpp -void OpenGL_Update() -{ -#if defined(USE_WX) && USE_WX - GLWin.glCanvas->GetSize((int *)&GLWin.width, (int *)&GLWin.height); - s_backbuffer_width = GLWin.width; - s_backbuffer_height = GLWin.height; -#elif defined(__APPLE__) - - // Is anything needed here? - -#elif defined(_WIN32) - RECT rcWindow; - if (!EmuWindow::GetParentWnd()) - { - // We are not rendering to a child window - use client size. - GetClientRect(EmuWindow::GetWnd(), &rcWindow); - } - else - { - // We are rendering to a child window - use parent size. - GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow); - } - - // Get the new window width and height - // See below for documentation - int width = rcWindow.right - rcWindow.left; - int height = rcWindow.bottom - rcWindow.top; - - // If we are rendering to a child window - if (EmuWindow::GetParentWnd() != 0 && (s_backbuffer_width != width || s_backbuffer_height != height) && width >= 4 && height >= 4) - { - ::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE); - s_backbuffer_width = width; - s_backbuffer_height = height; - } -#endif -} - - -// Close plugin -void OpenGL_Shutdown() -{ -#if defined(USE_WX) && USE_WX - delete GLWin.glCanvas; -#elif defined(__APPLE__) - cocoaGLDeleteWindow(GLWin.cocoaWin); - cocoaGLDelete(GLWin.cocoaCtx); - -#elif defined(_WIN32) - if (hRC) // Do We Have A Rendering Context? - { - if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? - { - // [F|RES]: if this fails i dont see the message box and - // cant get out of the modal state so i disable it. - // This function fails only if i render to main window - // MessageBox(NULL,"Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); - } - - if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? - { - ERROR_LOG(VIDEO, "Release Rendering Context Failed."); - } - hRC = NULL; // Set RC To NULL - } - - if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC - { - ERROR_LOG(VIDEO, "Release Device Context Failed."); - hDC = NULL; // Set DC To NULL - } - EmuWindow::Close(); -#elif defined(HAVE_X11) && HAVE_X11 - DestroyXWindow(); - if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL)) - NOTICE_LOG(VIDEO, "Could not release drawing context."); - if (GLWin.ctx) - { - glXDestroyContext(GLWin.dpy, GLWin.ctx); - XCloseDisplay(GLWin.dpy); - GLWin.ctx = NULL; - } -#endif -} - -GLuint OpenGL_ReportGLError(const char *function, const char *file, int line) -{ - GLint err = glGetError(); - if (err != GL_NO_ERROR) - { - ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n", file, line, function, err, gluErrorString(err)); - } - return err; -} - -void OpenGL_ReportARBProgramError() -{ - const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); - if (pstr != NULL && pstr[0] != 0) - { - GLint loc = 0; - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); - ERROR_LOG(VIDEO, "program error at %d: ", loc); - ERROR_LOG(VIDEO, (char*)pstr); - ERROR_LOG(VIDEO, ""); - } -} - -bool OpenGL_ReportFBOError(const char *function, const char *file, int line) -{ - unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - const char *error = "-"; - switch (fbo_status) - { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error = "INCOMPLETE_ATTACHMENT_EXT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error = "INCOMPLETE_MISSING_ATTACHMENT_EXT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error = "INCOMPLETE_DIMENSIONS_EXT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error = "INCOMPLETE_FORMATS_EXT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error = "INCOMPLETE_DRAW_BUFFER_EXT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error = "INCOMPLETE_READ_BUFFER_EXT"; break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error = "UNSUPPORTED_EXT"; break; - } - ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n", file, line, function, error); - return false; - } - return true; -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "IniFile.h" +#include "Setup.h" + +// VideoCommon +#include "VideoConfig.h" + +// OGL +#include "OGL_Render.h" +#include "OGL_GLUtil.h" + +#ifdef _WIN32 +#include "../EmuWindow.h" +extern HINSTANCE g_hInstance; +#endif + +namespace OGL +{ + +#ifdef _WIN32 +static HDC hDC = NULL; // Private GDI Device Context +static HGLRC hRC = NULL; // Permanent Rendering Context +#else +GLWindow GLWin; +#endif + +// Handles OpenGL and the window + +// Window dimensions. +static int s_backbuffer_width; +static int s_backbuffer_height; + +void OpenGL_SwapBuffers() +{ +#if defined(USE_WX) && USE_WX + GLWin.glCanvas->SwapBuffers(); +#elif defined(__APPLE__) + cocoaGLSwap(GLWin.cocoaCtx,GLWin.cocoaWin); +#elif defined(_WIN32) + SwapBuffers(hDC); +#elif defined(HAVE_X11) && HAVE_X11 + glXSwapBuffers(GLWin.dpy, GLWin.win); +#endif +} + +u32 OpenGL_GetBackbufferWidth() +{ + return s_backbuffer_width; +} + +u32 OpenGL_GetBackbufferHeight() +{ + return s_backbuffer_height; +} + +void OpenGL_SetWindowText(const char *text) +{ +#if defined(USE_WX) && USE_WX + // GLWin.frame->SetTitle(wxString::FromAscii(text)); +#elif defined(__APPLE__) + cocoaGLSetTitle(GLWin.cocoaWin, text); +#elif defined(_WIN32) + // TODO convert text to unicode and change SetWindowTextA to SetWindowText + SetWindowTextA(EmuWindow::GetWnd(), text); +#elif defined(HAVE_X11) && HAVE_X11 + // Tell X to ask the window manager to set the window title. + // (X itself doesn't provide window title functionality.) + XStoreName(GLWin.dpy, GLWin.win, text); +#endif +} + +#if defined(HAVE_X11) && HAVE_X11 +THREAD_RETURN XEventThread(void *pArg); + +void CreateXWindow (void) +{ + Atom wmProtocols[1]; + + // Setup window attributes + GLWin.attr.colormap = XCreateColormap(GLWin.dpy, + GLWin.parent, GLWin.vi->visual, AllocNone); + GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask; + GLWin.attr.background_pixel = BlackPixel(GLWin.dpy, GLWin.screen); + GLWin.attr.border_pixel = 0; + + // Create the window + GLWin.win = XCreateWindow(GLWin.dpy, GLWin.parent, + GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, GLWin.vi->depth, InputOutput, GLWin.vi->visual, + CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr); + wmProtocols[0] = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(GLWin.dpy, GLWin.win, wmProtocols, 1); + XSetStandardProperties(GLWin.dpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL); + XMapRaised(GLWin.dpy, GLWin.win); + XSync(GLWin.dpy, True); + + GLWin.xEventThread = new Common::Thread(XEventThread, NULL); +} + +void DestroyXWindow(void) +{ + XUnmapWindow(GLWin.dpy, GLWin.win); + GLWin.win = 0; + XFreeColormap(GLWin.dpy, GLWin.attr.colormap); + if (GLWin.xEventThread) + GLWin.xEventThread->WaitForDeath(); + GLWin.xEventThread = NULL; +} + +THREAD_RETURN XEventThread(void *pArg) +{ + while (GLWin.win) + { + XEvent event; + KeySym key; + for (int num_events = XPending(GLWin.dpy); num_events > 0; num_events--) { + XNextEvent(GLWin.dpy, &event); + switch(event.type) { + case KeyPress: + key = XLookupKeysym((XKeyEvent*)&event, 0); + switch (key) + { + case XK_3: + OSDChoice = 1; + // Toggle native resolution + if (!(g_Config.bNativeResolution || g_Config.b2xResolution)) + g_Config.bNativeResolution = true; + else if (g_Config.bNativeResolution && Renderer::AllowCustom()) + { + g_Config.bNativeResolution = false; + if (Renderer::Allow2x()) + g_Config.b2xResolution = true; + } + else if (Renderer::AllowCustom()) + g_Config.b2xResolution = false; + break; + case XK_4: + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + break; + case XK_5: + OSDChoice = 3; + // Toggle EFB copy + if (g_Config.bEFBCopyDisable || g_Config.bCopyEFBToTexture) + { + g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable; + g_Config.bCopyEFBToTexture = false; + } + else + { + g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; + } + break; + case XK_6: + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + break; + case XK_7: + OSDChoice = 5; + g_Config.bDisableLighting = !g_Config.bDisableLighting; + break; + default: + break; + } + break; + case ConfigureNotify: + Window winDummy; + unsigned int borderDummy, depthDummy; + XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &depthDummy); + s_backbuffer_width = GLWin.width; + s_backbuffer_height = GLWin.height; + break; + case ClientMessage: + if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", False)) + g_VideoInitialize.pCoreMessage(WM_USER_STOP); + if ((unsigned long) event.xclient.data.l[0] == XInternAtom(GLWin.dpy, "RESIZE", False)) + XMoveResizeWindow(GLWin.dpy, GLWin.win, event.xclient.data.l[1], + event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]); + break; + default: + break; + } + } + Common::SleepCurrentThread(20); + } + return 0; +} +#endif + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _iwidth, int _iheight) +{ + int _tx, _ty, _twidth, _theight; + g_VideoInitialize.pRequestWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + +#if defined(USE_WX) && USE_WX + int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0}; + + wxSize size(_twidth, _theight); + + GLWin.panel = (wxPanel *)g_VideoInitialize.pWindowHandle; + + GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, args, + wxPoint(0,0), size, wxSUNKEN_BORDER); + GLWin.glCtxt = new wxGLContext(GLWin.glCanvas); + GLWin.glCanvas->Show(TRUE); + + GLWin.glCanvas->SetCurrent(*GLWin.glCtxt); + +#elif defined(__APPLE__) + GLWin.width = s_backbuffer_width; + GLWin.height = s_backbuffer_height; + GLWin.cocoaWin = cocoaGLCreateWindow(GLWin.width, GLWin.height); + GLWin.cocoaCtx = cocoaGLInit(g_Config.iMultisampleMode); + +#elif defined(_WIN32) + + PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24Bit Z-Buffer (Depth Buffer) + 8, // 8bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + GLuint PixelFormat; // Holds The Results After Searching For A Match + + if (!(hDC=GetDC(EmuWindow::GetWnd()))) { + PanicAlert("(1) Can't create an OpenGL Device context. Fail."); + return false; + } + if (!(PixelFormat = ChoosePixelFormat(hDC,&pfd))) { + PanicAlert("(2) Can't find a suitable PixelFormat."); + return false; + } + if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { + PanicAlert("(3) Can't set the PixelFormat."); + return false; + } + if (!(hRC = wglCreateContext(hDC))) { + PanicAlert("(4) Can't create an OpenGL rendering context."); + return false; + } + // -------------------------------------- + +#elif defined(HAVE_X11) && HAVE_X11 + int glxMajorVersion, glxMinorVersion; + + // attributes for a single buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None}; + + // attributes for a double buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, + GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, + None }; + + int attrListDefault[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None }; + + GLWin.dpy = XOpenDisplay(0); + GLWin.parent = (Window)g_VideoInitialize.pWindowHandle; + GLWin.screen = DefaultScreen(GLWin.dpy); + if (GLWin.parent == 0) + GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen); + + glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); + NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion); + + // Get an appropriate visual + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); + if (GLWin.vi == NULL) + { + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); + if (GLWin.vi != NULL) + { + ERROR_LOG(VIDEO, "Only Singlebuffered Visual!"); + } + else + { + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault); + if (GLWin.vi == NULL) + { + ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)"); + exit(0); + } + } + } + else + NOTICE_LOG(VIDEO, "Got Doublebuffered Visual!"); + + // Create a GLX context. + GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE); + if (!GLWin.ctx) + { + PanicAlert("Couldn't Create GLX context.Quit"); + exit(0); // TODO: Don't bring down entire Emu + } + + GLWin.x = _tx; + GLWin.y = _ty; + GLWin.width = _twidth; + GLWin.height = _theight; + + CreateXWindow(); + g_VideoInitialize.pWindowHandle = (void *)GLWin.win; +#endif + return true; +} + +bool OpenGL_MakeCurrent() +{ + // connect the glx-context to the window +#if defined(USE_WX) && USE_WX + GLWin.glCanvas->SetCurrent(*GLWin.glCtxt); +#elif defined(__APPLE__) + cocoaGLMakeCurrent(GLWin.cocoaCtx,GLWin.cocoaWin); +#elif defined(_WIN32) + return wglMakeCurrent(hDC,hRC) ? true : false; +#elif defined(HAVE_X11) && HAVE_X11 +#if defined(HAVE_WX) && (HAVE_WX) + g_VideoInitialize.pRequestWindowSize(GLWin.x, GLWin.y, (int&)GLWin.width, (int&)GLWin.height); + XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, GLWin.width, GLWin.height); +#endif + return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); +#endif + return true; +} + +// Update window width, size and etc. Called from Render.cpp +void OpenGL_Update() +{ +#if defined(USE_WX) && USE_WX + GLWin.glCanvas->GetSize((int *)&GLWin.width, (int *)&GLWin.height); + s_backbuffer_width = GLWin.width; + s_backbuffer_height = GLWin.height; +#elif defined(__APPLE__) + + // Is anything needed here? + +#elif defined(_WIN32) + RECT rcWindow; + if (!EmuWindow::GetParentWnd()) + { + // We are not rendering to a child window - use client size. + GetClientRect(EmuWindow::GetWnd(), &rcWindow); + } + else + { + // We are rendering to a child window - use parent size. + GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow); + } + + // Get the new window width and height + // See below for documentation + int width = rcWindow.right - rcWindow.left; + int height = rcWindow.bottom - rcWindow.top; + + // If we are rendering to a child window + if (EmuWindow::GetParentWnd() != 0 && (s_backbuffer_width != width || s_backbuffer_height != height) && width >= 4 && height >= 4) + { + ::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE); + s_backbuffer_width = width; + s_backbuffer_height = height; + } +#endif +} + + +// Close plugin +void OpenGL_Shutdown() +{ +#if defined(USE_WX) && USE_WX + delete GLWin.glCanvas; +#elif defined(__APPLE__) + cocoaGLDeleteWindow(GLWin.cocoaWin); + cocoaGLDelete(GLWin.cocoaCtx); + +#elif defined(_WIN32) + if (hRC) // Do We Have A Rendering Context? + { + if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts? + { + // [F|RES]: if this fails i dont see the message box and + // cant get out of the modal state so i disable it. + // This function fails only if i render to main window + // MessageBox(NULL,"Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); + } + + if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? + { + ERROR_LOG(VIDEO, "Release Rendering Context Failed."); + } + hRC = NULL; // Set RC To NULL + } + + if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC + { + ERROR_LOG(VIDEO, "Release Device Context Failed."); + hDC = NULL; // Set DC To NULL + } + EmuWindow::Close(); +#elif defined(HAVE_X11) && HAVE_X11 + DestroyXWindow(); + if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); + if (GLWin.ctx) + { + glXDestroyContext(GLWin.dpy, GLWin.ctx); + XCloseDisplay(GLWin.dpy); + GLWin.ctx = NULL; + } +#endif +} + +GLuint OpenGL_ReportGLError(const char *function, const char *file, int line) +{ + GLint err = glGetError(); + if (err != GL_NO_ERROR) + { + ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL error 0x%x - %s\n", file, line, function, err, gluErrorString(err)); + } + return err; +} + +void OpenGL_ReportARBProgramError() +{ + const GLubyte* pstr = glGetString(GL_PROGRAM_ERROR_STRING_ARB); + if (pstr != NULL && pstr[0] != 0) + { + GLint loc = 0; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc); + ERROR_LOG(VIDEO, "program error at %d: ", loc); + ERROR_LOG(VIDEO, (char*)pstr); + ERROR_LOG(VIDEO, ""); + } +} + +bool OpenGL_ReportFBOError(const char *function, const char *file, int line) +{ + unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) + { + const char *error = "-"; + switch (fbo_status) + { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error = "INCOMPLETE_ATTACHMENT_EXT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error = "INCOMPLETE_MISSING_ATTACHMENT_EXT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error = "INCOMPLETE_DIMENSIONS_EXT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error = "INCOMPLETE_FORMATS_EXT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error = "INCOMPLETE_DRAW_BUFFER_EXT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error = "INCOMPLETE_READ_BUFFER_EXT"; break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error = "UNSUPPORTED_EXT"; break; + } + ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n", file, line, function, error); + return false; + } + return true; +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.h index 1255fd6fca..531ae688cb 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLUtil.h @@ -1,145 +1,145 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _GLINIT_H_ -#define _GLINIT_H_ - -// Common -#include "MathUtil.h" - -// VideoCommon -#include "VideoConfig.h" - -#include "pluginspecs_video.h" - -#ifdef _WIN32 - -#define GLEW_STATIC - -#include -#include - -#else // linux and apple basic definitions - -#if defined(USE_WX) && USE_WX -#include -#include "wx/wx.h" -#include "wx/glcanvas.h" - -#elif defined(HAVE_X11) && HAVE_X11 -#include -#include -#include -#include "Thread.h" - -#elif defined(__APPLE__) -#include -#include "cocoaGL.h" -#endif // end USE_WX - -#if defined(__APPLE__) -#include -#else -#include -#endif - -#endif // linux basic definitions - -#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -#ifndef _WIN32 - -#include - -typedef struct { -#if defined(USE_WX) && USE_WX - wxGLCanvas *glCanvas; - wxPanel *panel; - wxGLContext *glCtxt; -#elif defined(__APPLE__) - NSWindow *cocoaWin; - NSOpenGLContext *cocoaCtx; -#elif defined(HAVE_X11) && HAVE_X11 - int screen; - Window win; - Window parent; - Display *dpy; - XVisualInfo *vi; - GLXContext ctx; - XSetWindowAttributes attr; - Common::Thread *xEventThread; - int x, y; -#endif - unsigned int width, height; -} GLWindow; - -extern GLWindow GLWin; - -#endif - -// Public OpenGL util - -//#if defined __APPLE__ || defined __linux__ || defined _WIN32 -//#include -//#include -//#define HAVE_CG 1 -//extern CGcontext g_cgcontext; -//extern CGprofile g_cgvProf, g_cgfProf; -//#endif - -namespace OGL -{ - -// Initialization / upkeep -bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height); -void OpenGL_Shutdown(); -void OpenGL_Update(); -bool OpenGL_MakeCurrent(); -void OpenGL_SwapBuffers(); - -// Get status -u32 OpenGL_GetBackbufferWidth(); -u32 OpenGL_GetBackbufferHeight(); - -// Set things -void OpenGL_SetWindowText(const char *text); - -// Error reporting - use the convenient macros. -void OpenGL_ReportARBProgramError(); -GLuint OpenGL_ReportGLError(const char *function, const char *file, int line); -bool OpenGL_ReportFBOError(const char *function, const char *file, int line); - -#if defined(_DEBUG) || defined(DEBUGFAST) -#define GL_REPORT_ERROR() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__) -#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__) -#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError(__FUNCTION__, __FILE__, __LINE__) -#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError() -#else -#define GL_REPORT_ERROR() GL_NO_ERROR -#define GL_REPORT_ERRORD() (void)GL_NO_ERROR -#define GL_REPORT_FBO_ERROR() (void)true -#define GL_REPORT_PROGRAM_ERROR() (void)0 -#endif - -} - -#endif // _GLINIT_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _GLINIT_H_ +#define _GLINIT_H_ + +// Common +#include "MathUtil.h" + +// VideoCommon +#include "VideoConfig.h" + +#include "pluginspecs_video.h" + +#ifdef _WIN32 + +#define GLEW_STATIC + +#include +#include + +#else // linux and apple basic definitions + +#if defined(USE_WX) && USE_WX +#include +#include "wx/wx.h" +#include "wx/glcanvas.h" + +#elif defined(HAVE_X11) && HAVE_X11 +#include +#include +#include +#include "Thread.h" + +#elif defined(__APPLE__) +#include +#include "cocoaGL.h" +#endif // end USE_WX + +#if defined(__APPLE__) +#include +#else +#include +#endif + +#endif // linux basic definitions + +#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif + +#ifndef _WIN32 + +#include + +typedef struct { +#if defined(USE_WX) && USE_WX + wxGLCanvas *glCanvas; + wxPanel *panel; + wxGLContext *glCtxt; +#elif defined(__APPLE__) + NSWindow *cocoaWin; + NSOpenGLContext *cocoaCtx; +#elif defined(HAVE_X11) && HAVE_X11 + int screen; + Window win; + Window parent; + Display *dpy; + XVisualInfo *vi; + GLXContext ctx; + XSetWindowAttributes attr; + Common::Thread *xEventThread; + int x, y; +#endif + unsigned int width, height; +} GLWindow; + +extern GLWindow GLWin; + +#endif + +// Public OpenGL util + +//#if defined __APPLE__ || defined __linux__ || defined _WIN32 +//#include +//#include +//#define HAVE_CG 1 +//extern CGcontext g_cgcontext; +//extern CGprofile g_cgvProf, g_cgfProf; +//#endif + +namespace OGL +{ + +// Initialization / upkeep +bool OpenGL_Create(SVideoInitialize &_VideoInitialize, int _width, int _height); +void OpenGL_Shutdown(); +void OpenGL_Update(); +bool OpenGL_MakeCurrent(); +void OpenGL_SwapBuffers(); + +// Get status +u32 OpenGL_GetBackbufferWidth(); +u32 OpenGL_GetBackbufferHeight(); + +// Set things +void OpenGL_SetWindowText(const char *text); + +// Error reporting - use the convenient macros. +void OpenGL_ReportARBProgramError(); +GLuint OpenGL_ReportGLError(const char *function, const char *file, int line); +bool OpenGL_ReportFBOError(const char *function, const char *file, int line); + +#if defined(_DEBUG) || defined(DEBUGFAST) +#define GL_REPORT_ERROR() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__) +#define GL_REPORT_ERRORD() OpenGL_ReportGLError(__FUNCTION__, __FILE__, __LINE__) +#define GL_REPORT_FBO_ERROR() OpenGL_ReportFBOError(__FUNCTION__, __FILE__, __LINE__) +#define GL_REPORT_PROGRAM_ERROR() OpenGL_ReportARBProgramError() +#else +#define GL_REPORT_ERROR() GL_NO_ERROR +#define GL_REPORT_ERRORD() (void)GL_NO_ERROR +#define GL_REPORT_FBO_ERROR() (void)true +#define GL_REPORT_PROGRAM_ERROR() (void)0 +#endif + +} + +#endif // _GLINIT_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLWindow.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLWindow.h index fd9a000309..2d697eac20 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLWindow.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_GLWindow.h @@ -1,178 +1,178 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_GLWINDOW_H_ -#define _OGL_GLWINDOW_H_ - -#include - -#include "Common.h" - -#include "OGL_Globals.h" - -#include "pluginspecs_video.h" - -#ifdef _WIN32 -#define GLEW_STATIC - -#include -#include -#include -#include -#else -#include -#endif - -#if defined(__APPLE__) -#include -#else -#include -#endif - -namespace OGL -{ - -enum OGL_Props -{ - OGL_FULLSCREEN, - OGL_KEEPRATIO, - OGL_HIDECURSOR, - OGL_PROP_COUNT -}; - -struct res -{ - u32 x; - u32 y; -}; - -class GLWindow -{ -private: - - // TODO: what is xmax and ymax? do we need [xy]render? - u32 xWin, yWin; // Windows' size - int xOffset, yOffset; // Offset in window - float xMax, yMax; // ??? - u32 xRender, yRender; // Render area - - bool properties[OGL_PROP_COUNT]; - -protected: - - EventHandler* eventHandler; - res origRes, currFullRes, currWinRes; - static std::vector fullResolutions; - virtual void SetRender(u32 x, u32 y) - { - xRender = x; - yRender = y; - } - - static const std::vector& getFsResolutions() - { - return fullResolutions; - } - - static void addFSResolution(res fsr) - { - fullResolutions.push_back(fsr); - } -public: - - virtual void SwapBuffers() {}; - virtual void SetWindowText(const char *text) {}; - virtual bool PeekMessages() {return false;}; - virtual void Update() {}; - virtual bool MakeCurrent() {return false;}; - - virtual void updateDim() - { - if (GetProperty(OGL_FULLSCREEN)) - SetWinSize(currFullRes.x, currFullRes.y); - else - // Set the windowed resolution - SetWinSize(currWinRes.x, currWinRes.y); - - float FactorX = 640.0f / (float)GetXwin(); - float FactorY = 480.0f / (float)GetYwin(); - //float Max = (FactorX < FactorY) ? FactorX : FactorY; - - SetMax(1.0f / FactorX, 1.0f / FactorY); - SetOffset(0,0); - } - - void SetEventHandler(EventHandler *eh) { eventHandler = eh;} - bool GetProperty(OGL_Props prop) {return properties[prop];} - virtual bool SetProperty(OGL_Props prop, bool value) - {return properties[prop] = value;} - - u32 GetXrender() {return xRender;} - u32 GetYrender() {return yRender;} - - u32 GetXwin() {return xWin;} - u32 GetYwin() {return yWin;} - void SetWinSize(u32 x, u32 y) - { - xWin = x; - yWin = y; - } - - int GetYoff() {return yOffset;} - int GetXoff() {return xOffset;} - void SetOffset(int x, int y) - { - yOffset = y; - xOffset = x; - } - - void SetMax(float x, float y) - { - yMax = y; - xMax = x; - } - - float GetXmax() {return xMax;} - float GetYmax() {return yMax;} - - static bool valid() { return false;} - - GLWindow() - { - // Load defaults - sscanf(g_Config.iFSResolution, "%dx%d", - &currFullRes.x, &currFullRes.y); - - sscanf(g_Config.iInternalRes, "%dx%d", - &currWinRes.x, &currWinRes.y); - - SetProperty(OGL_FULLSCREEN, g_Config.bFullscreen); - // What does this do? - SetProperty(OGL_KEEPRATIO, g_Config.bKeepAR43); - SetProperty(OGL_HIDECURSOR, g_Config.bHideCursor); - - updateDim(); - } - - - // setResolution - // resolution iter -}; - -} - -#endif // _GLWINDOW_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_GLWINDOW_H_ +#define _OGL_GLWINDOW_H_ + +#include + +#include "Common.h" + +#include "OGL_Globals.h" + +#include "pluginspecs_video.h" + +#ifdef _WIN32 +#define GLEW_STATIC + +#include +#include +#include +#include +#else +#include +#endif + +#if defined(__APPLE__) +#include +#else +#include +#endif + +namespace OGL +{ + +enum OGL_Props +{ + OGL_FULLSCREEN, + OGL_KEEPRATIO, + OGL_HIDECURSOR, + OGL_PROP_COUNT +}; + +struct res +{ + u32 x; + u32 y; +}; + +class GLWindow +{ +private: + + // TODO: what is xmax and ymax? do we need [xy]render? + u32 xWin, yWin; // Windows' size + int xOffset, yOffset; // Offset in window + float xMax, yMax; // ??? + u32 xRender, yRender; // Render area + + bool properties[OGL_PROP_COUNT]; + +protected: + + EventHandler* eventHandler; + res origRes, currFullRes, currWinRes; + static std::vector fullResolutions; + virtual void SetRender(u32 x, u32 y) + { + xRender = x; + yRender = y; + } + + static const std::vector& getFsResolutions() + { + return fullResolutions; + } + + static void addFSResolution(res fsr) + { + fullResolutions.push_back(fsr); + } +public: + + virtual void SwapBuffers() {}; + virtual void SetWindowText(const char *text) {}; + virtual bool PeekMessages() {return false;}; + virtual void Update() {}; + virtual bool MakeCurrent() {return false;}; + + virtual void updateDim() + { + if (GetProperty(OGL_FULLSCREEN)) + SetWinSize(currFullRes.x, currFullRes.y); + else + // Set the windowed resolution + SetWinSize(currWinRes.x, currWinRes.y); + + float FactorX = 640.0f / (float)GetXwin(); + float FactorY = 480.0f / (float)GetYwin(); + //float Max = (FactorX < FactorY) ? FactorX : FactorY; + + SetMax(1.0f / FactorX, 1.0f / FactorY); + SetOffset(0,0); + } + + void SetEventHandler(EventHandler *eh) { eventHandler = eh;} + bool GetProperty(OGL_Props prop) {return properties[prop];} + virtual bool SetProperty(OGL_Props prop, bool value) + {return properties[prop] = value;} + + u32 GetXrender() {return xRender;} + u32 GetYrender() {return yRender;} + + u32 GetXwin() {return xWin;} + u32 GetYwin() {return yWin;} + void SetWinSize(u32 x, u32 y) + { + xWin = x; + yWin = y; + } + + int GetYoff() {return yOffset;} + int GetXoff() {return xOffset;} + void SetOffset(int x, int y) + { + yOffset = y; + xOffset = x; + } + + void SetMax(float x, float y) + { + yMax = y; + xMax = x; + } + + float GetXmax() {return xMax;} + float GetYmax() {return yMax;} + + static bool valid() { return false;} + + GLWindow() + { + // Load defaults + sscanf(g_Config.iFSResolution, "%dx%d", + &currFullRes.x, &currFullRes.y); + + sscanf(g_Config.iInternalRes, "%dx%d", + &currWinRes.x, &currWinRes.y); + + SetProperty(OGL_FULLSCREEN, g_Config.bFullscreen); + // What does this do? + SetProperty(OGL_KEEPRATIO, g_Config.bKeepAR43); + SetProperty(OGL_HIDECURSOR, g_Config.bHideCursor); + + updateDim(); + } + + + // setResolution + // resolution iter +}; + +} + +#endif // _GLWINDOW_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_NativeVertexFormat.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_NativeVertexFormat.cpp index 175b352ff4..6b763494d8 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_NativeVertexFormat.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_NativeVertexFormat.cpp @@ -1,310 +1,310 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "x64Emitter.h" -#include "ABI.h" -#include "MemoryUtil.h" - -// VideoCommon -#include "Profiler.h" -#include "VertexShaderGen.h" -#include "NativeVertexFormat.h" -#include "NativeVertexWriter.h" -#include "CPMemory.h" - -// OGL -#include "OGL_GLUtil.h" -#include "OGL_VertexManager.h" - -#include "../Main.h" - -namespace OGL -{ - -#define COMPILED_CODE_SIZE 4096 - -u32 s_prevcomponents; // previous state set -/* -#ifdef _WIN32 -#ifdef _M_IX86 -#define USE_JIT -#endif -#endif -*/ -// Note the use of CallCdeclFunction3I etc. -// This is a horrible hack that is necessary because in 64-bit mode, Opengl32.dll is based way, way above the 32-bit -// address space that is within reach of a CALL, and just doing &fn gives us these high uncallable addresses. So we -// want to grab the function pointers from the import table instead. - -// This problem does not apply to glew functions, only core opengl32 functions. - -// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state -// machine. - -#ifdef USE_JIT -DECLARE_IMPORT(glNormalPointer); -DECLARE_IMPORT(glVertexPointer); -DECLARE_IMPORT(glColorPointer); -DECLARE_IMPORT(glTexCoordPointer); -#endif - -class GLVertexFormat : public NativeVertexFormat -{ - u8 *m_compiledCode; - PortableVertexDeclaration vtx_decl; - -public: - GLVertexFormat(); - ~GLVertexFormat(); - - virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); - virtual void SetupVertexPointers() const; - virtual void EnableComponents(u32 components); -}; - -NativeVertexFormat* VertexManager::CreateNativeVertexFormat() -{ - return new GLVertexFormat; -} - -GLVertexFormat::GLVertexFormat() -{ -#ifdef USE_JIT - m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false); - if (m_compiledCode) - memset(m_compiledCode, 0, COMPILED_CODE_SIZE); -#endif -} - -GLVertexFormat::~GLVertexFormat() -{ -#ifdef USE_JIT - FreeMemoryPages(m_compiledCode, COMPILED_CODE_SIZE); - m_compiledCode = 0; -#endif -} - -inline GLuint VarToGL(VarType t) -{ - static const GLuint lookup[5] = { - GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT - }; - return lookup[t]; -} - -void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) -{ - vertex_stride = _vtx_decl.stride; - using namespace Gen; - - // We will not allow vertex components causing uneven strides. - if (_vtx_decl.stride & 3) - PanicAlert("Uneven vertex stride: %i", _vtx_decl.stride); - -#ifdef USE_JIT - Gen::XEmitter emit(m_compiledCode); - // Alright, we have our vertex declaration. Compile some crazy code to set it quickly using GL. - emit.ABI_EmitPrologue(6); - - emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0); - - if (_vtx_decl.num_normals >= 1) - { - emit.CallCdeclFunction3_I(glNormalPointer, VarToGL(_vtx_decl.normal_gl_type), _vtx_decl.stride, _vtx_decl.normal_offset[0]); - if (_vtx_decl.num_normals == 3) { - emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM1_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[1]); - emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM2_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[2]); - } - } - - for (int i = 0; i < 2; i++) - { - if (_vtx_decl.color_offset[i] != -1) - { - if (i == 0) - emit.CallCdeclFunction4_I(glColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]); - else - emit.CallCdeclFunction4((void *)glSecondaryColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]); - } - } - - for (int i = 0; i < 8; i++) - { - if (_vtx_decl.texcoord_offset[i] != -1) - { - int id = GL_TEXTURE0 + i; -#ifdef _M_X64 -#ifdef _MSC_VER - emit.MOV(32, R(RCX), Imm32(id)); -#else - emit.MOV(32, R(RDI), Imm32(id)); -#endif -#else - emit.ABI_AlignStack(1 * 4); - emit.PUSH(32, Imm32(id)); -#endif - emit.CALL((void *)glClientActiveTexture); -#ifndef _M_X64 -#ifdef _WIN32 - // don't inc stack on windows, stdcall -#else - emit.ABI_RestoreStack(1 * 4); -#endif -#endif - emit.CallCdeclFunction4_I( - glTexCoordPointer, _vtx_decl.texcoord_size[i], VarToGL(_vtx_decl.texcoord_gl_type[i]), - _vtx_decl.stride, _vtx_decl.texcoord_offset[i]); - } - } - - if (_vtx_decl.posmtx_offset != -1) - emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, _vtx_decl.stride, _vtx_decl.posmtx_offset); - - emit.ABI_EmitEpilogue(6); - - if (emit.GetCodePtr() - (u8*)m_compiledCode > COMPILED_CODE_SIZE) - Crash(); - -#endif - this->vtx_decl = _vtx_decl; -} - -void GLVertexFormat::SetupVertexPointers() const { - // Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to - // get around type checking errors, and call it. -#ifdef USE_JIT - ((void (*)())(void*)m_compiledCode)(); -#else - glVertexPointer(3, GL_FLOAT, vtx_decl.stride, ::VertexManager::s_pBaseBufferPointer); - if (vtx_decl.num_normals >= 1) { - glNormalPointer(VarToGL(vtx_decl.normal_gl_type), vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[0])); - if (vtx_decl.num_normals == 3) { - glVertexAttribPointer(SHADER_NORM1_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[1])); - glVertexAttribPointer(SHADER_NORM2_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[2])); - } - } - - for (int i = 0; i < 2; i++) { - if (vtx_decl.color_offset[i] != -1) { - if (i == 0) - glColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i])); - else { - glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i])); - } - } - } - - for (int i = 0; i < 8; i++) { - if (vtx_decl.texcoord_offset[i] != -1) { - int id = GL_TEXTURE0 + i; - glClientActiveTexture(id); - glTexCoordPointer(vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]), - vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.texcoord_offset[i])); - } - } - - if (vtx_decl.posmtx_offset != -1) { - glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset)); - } -#endif -} - -void GLVertexFormat::EnableComponents(u32 components) -{ - if (s_prevcomponents != components) - { - g_vertex_manager->Flush(); - - // matrices - if ((components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX)) - { - if (components & VB_HAS_POSMTXIDX) - glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB); - else - glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB); - } - - // normals - if ((components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0)) - { - if (components & VB_HAS_NRM0) - glEnableClientState(GL_NORMAL_ARRAY); - else - glDisableClientState(GL_NORMAL_ARRAY); - } - if ((components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1)) - { - if (components & VB_HAS_NRM1) { - glEnableVertexAttribArray(SHADER_NORM1_ATTRIB); - glEnableVertexAttribArray(SHADER_NORM2_ATTRIB); - } - else { - glDisableVertexAttribArray(SHADER_NORM1_ATTRIB); - glDisableVertexAttribArray(SHADER_NORM2_ATTRIB); - } - } - - // color - for (int i = 0; i < 2; ++i) - { - if ((components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i))) - { - if (components & (VB_HAS_COL0 << i)) - glEnableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY); - else - glDisableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY); - } - } - - // tex - for (int i = 0; i < 8; ++i) - { - if (!g_ActiveConfig.bDisableTexturing) - { - if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i))) - { - glClientActiveTexture(GL_TEXTURE0 + i); - if (components & (VB_HAS_UV0 << i)) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - else - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - } - else - { - glClientActiveTexture(GL_TEXTURE0 + i); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - } - - // Disable Lighting - // TODO - Is this a good spot for this code? - if (g_ActiveConfig.bDisableLighting) - { - for (int i = 0; i < xfregs.nNumChans; i++) - { - xfregs.colChans[i].alpha.enablelighting = false; - xfregs.colChans[i].color.enablelighting = false; - } - } - - s_prevcomponents = components; - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "x64Emitter.h" +#include "ABI.h" +#include "MemoryUtil.h" + +// VideoCommon +#include "Profiler.h" +#include "VertexShaderGen.h" +#include "NativeVertexFormat.h" +#include "NativeVertexWriter.h" +#include "CPMemory.h" + +// OGL +#include "OGL_GLUtil.h" +#include "OGL_VertexManager.h" + +#include "../Main.h" + +namespace OGL +{ + +#define COMPILED_CODE_SIZE 4096 + +u32 s_prevcomponents; // previous state set +/* +#ifdef _WIN32 +#ifdef _M_IX86 +#define USE_JIT +#endif +#endif +*/ +// Note the use of CallCdeclFunction3I etc. +// This is a horrible hack that is necessary because in 64-bit mode, Opengl32.dll is based way, way above the 32-bit +// address space that is within reach of a CALL, and just doing &fn gives us these high uncallable addresses. So we +// want to grab the function pointers from the import table instead. + +// This problem does not apply to glew functions, only core opengl32 functions. + +// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state +// machine. + +#ifdef USE_JIT +DECLARE_IMPORT(glNormalPointer); +DECLARE_IMPORT(glVertexPointer); +DECLARE_IMPORT(glColorPointer); +DECLARE_IMPORT(glTexCoordPointer); +#endif + +class GLVertexFormat : public NativeVertexFormat +{ + u8 *m_compiledCode; + PortableVertexDeclaration vtx_decl; + +public: + GLVertexFormat(); + ~GLVertexFormat(); + + virtual void Initialize(const PortableVertexDeclaration &_vtx_decl); + virtual void SetupVertexPointers() const; + virtual void EnableComponents(u32 components); +}; + +NativeVertexFormat* VertexManager::CreateNativeVertexFormat() +{ + return new GLVertexFormat; +} + +GLVertexFormat::GLVertexFormat() +{ +#ifdef USE_JIT + m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false); + if (m_compiledCode) + memset(m_compiledCode, 0, COMPILED_CODE_SIZE); +#endif +} + +GLVertexFormat::~GLVertexFormat() +{ +#ifdef USE_JIT + FreeMemoryPages(m_compiledCode, COMPILED_CODE_SIZE); + m_compiledCode = 0; +#endif +} + +inline GLuint VarToGL(VarType t) +{ + static const GLuint lookup[5] = { + GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT + }; + return lookup[t]; +} + +void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl) +{ + vertex_stride = _vtx_decl.stride; + using namespace Gen; + + // We will not allow vertex components causing uneven strides. + if (_vtx_decl.stride & 3) + PanicAlert("Uneven vertex stride: %i", _vtx_decl.stride); + +#ifdef USE_JIT + Gen::XEmitter emit(m_compiledCode); + // Alright, we have our vertex declaration. Compile some crazy code to set it quickly using GL. + emit.ABI_EmitPrologue(6); + + emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0); + + if (_vtx_decl.num_normals >= 1) + { + emit.CallCdeclFunction3_I(glNormalPointer, VarToGL(_vtx_decl.normal_gl_type), _vtx_decl.stride, _vtx_decl.normal_offset[0]); + if (_vtx_decl.num_normals == 3) { + emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM1_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[1]); + emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM2_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[2]); + } + } + + for (int i = 0; i < 2; i++) + { + if (_vtx_decl.color_offset[i] != -1) + { + if (i == 0) + emit.CallCdeclFunction4_I(glColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]); + else + emit.CallCdeclFunction4((void *)glSecondaryColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]); + } + } + + for (int i = 0; i < 8; i++) + { + if (_vtx_decl.texcoord_offset[i] != -1) + { + int id = GL_TEXTURE0 + i; +#ifdef _M_X64 +#ifdef _MSC_VER + emit.MOV(32, R(RCX), Imm32(id)); +#else + emit.MOV(32, R(RDI), Imm32(id)); +#endif +#else + emit.ABI_AlignStack(1 * 4); + emit.PUSH(32, Imm32(id)); +#endif + emit.CALL((void *)glClientActiveTexture); +#ifndef _M_X64 +#ifdef _WIN32 + // don't inc stack on windows, stdcall +#else + emit.ABI_RestoreStack(1 * 4); +#endif +#endif + emit.CallCdeclFunction4_I( + glTexCoordPointer, _vtx_decl.texcoord_size[i], VarToGL(_vtx_decl.texcoord_gl_type[i]), + _vtx_decl.stride, _vtx_decl.texcoord_offset[i]); + } + } + + if (_vtx_decl.posmtx_offset != -1) + emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, _vtx_decl.stride, _vtx_decl.posmtx_offset); + + emit.ABI_EmitEpilogue(6); + + if (emit.GetCodePtr() - (u8*)m_compiledCode > COMPILED_CODE_SIZE) + Crash(); + +#endif + this->vtx_decl = _vtx_decl; +} + +void GLVertexFormat::SetupVertexPointers() const { + // Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to + // get around type checking errors, and call it. +#ifdef USE_JIT + ((void (*)())(void*)m_compiledCode)(); +#else + glVertexPointer(3, GL_FLOAT, vtx_decl.stride, ::VertexManager::s_pBaseBufferPointer); + if (vtx_decl.num_normals >= 1) { + glNormalPointer(VarToGL(vtx_decl.normal_gl_type), vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[0])); + if (vtx_decl.num_normals == 3) { + glVertexAttribPointer(SHADER_NORM1_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[1])); + glVertexAttribPointer(SHADER_NORM2_ATTRIB, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[2])); + } + } + + for (int i = 0; i < 2; i++) { + if (vtx_decl.color_offset[i] != -1) { + if (i == 0) + glColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i])); + else { + glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i])); + } + } + } + + for (int i = 0; i < 8; i++) { + if (vtx_decl.texcoord_offset[i] != -1) { + int id = GL_TEXTURE0 + i; + glClientActiveTexture(id); + glTexCoordPointer(vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]), + vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.texcoord_offset[i])); + } + } + + if (vtx_decl.posmtx_offset != -1) { + glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(::VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset)); + } +#endif +} + +void GLVertexFormat::EnableComponents(u32 components) +{ + if (s_prevcomponents != components) + { + g_vertex_manager->Flush(); + + // matrices + if ((components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX)) + { + if (components & VB_HAS_POSMTXIDX) + glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB); + else + glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB); + } + + // normals + if ((components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0)) + { + if (components & VB_HAS_NRM0) + glEnableClientState(GL_NORMAL_ARRAY); + else + glDisableClientState(GL_NORMAL_ARRAY); + } + if ((components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1)) + { + if (components & VB_HAS_NRM1) { + glEnableVertexAttribArray(SHADER_NORM1_ATTRIB); + glEnableVertexAttribArray(SHADER_NORM2_ATTRIB); + } + else { + glDisableVertexAttribArray(SHADER_NORM1_ATTRIB); + glDisableVertexAttribArray(SHADER_NORM2_ATTRIB); + } + } + + // color + for (int i = 0; i < 2; ++i) + { + if ((components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i))) + { + if (components & (VB_HAS_COL0 << i)) + glEnableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY); + else + glDisableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY); + } + } + + // tex + for (int i = 0; i < 8; ++i) + { + if (!g_ActiveConfig.bDisableTexturing) + { + if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i))) + { + glClientActiveTexture(GL_TEXTURE0 + i); + if (components & (VB_HAS_UV0 << i)) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + else + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } + else + { + glClientActiveTexture(GL_TEXTURE0 + i); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } + + // Disable Lighting + // TODO - Is this a good spot for this code? + if (g_ActiveConfig.bDisableLighting) + { + for (int i = 0; i < xfregs.nNumChans; i++) + { + xfregs.colChans[i].alpha.enablelighting = false; + xfregs.colChans[i].color.enablelighting = false; + } + } + + s_prevcomponents = components; + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.cpp index 24295f305f..eb419527b1 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.cpp @@ -1,340 +1,340 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -// Common -#include "Common.h" -#include "FileUtil.h" - -// VideoCommon -#include "Profiler.h" -#include "Statistics.h" -#include "VideoConfig.h" -#include "ImageWrite.h" -#include "PixelShaderManager.h" -#include "VertexShaderGen.h" - -// OGL -#include "OGL_Render.h" -#include "OGL_GLUtil.h" -#include "OGL_PixelShaderCache.h" - -#include "../Main.h" - -namespace OGL -{ - -static int s_nMaxPixelInstructions; -static GLuint s_ColorMatrixProgram = 0; -static GLuint s_DepthMatrixProgram = 0; -PixelShaderCache::PSCache PixelShaderCache::pshaders; -PIXELSHADERUID PixelShaderCache::s_curuid; -bool PixelShaderCache::s_displayCompileAlert; -GLuint PixelShaderCache::CurrentShader; -bool PixelShaderCache::ShaderEnabled; - -static FRAGMENTSHADER* pShaderLast = NULL; - - -void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - float f[4] = { f1, f2, f3, f4 }; - glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); - //SetPSConstant4fv(const_number, f); -} - -void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f) -{ - glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); -} - -void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) -{ - for (unsigned int i = 0; i < count; ++i, f+=4, ++const_number) - glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); - //SetPSConstant4fv(const_number, f); -} - -PixelShaderCache::PixelShaderCache() -{ - glEnable(GL_FRAGMENT_PROGRAM_ARB); - ShaderEnabled = true; - CurrentShader = 0; - GL_REPORT_ERRORD(); - - memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); - - s_displayCompileAlert = true; - - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions); -#if CG_VERSION_NUM == 2100 - if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL) - { - s_nMaxPixelInstructions = 4096; - } -#endif - - int maxinst, maxattribs; - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs); - INFO_LOG(VIDEO, "pixel max_alu=%d, max_inst=%d, max_attrib=%d", s_nMaxPixelInstructions, maxinst, maxattribs); - - char pmatrixprog[1024]; - sprintf(pmatrixprog, "!!ARBfp1.0" - "TEMP R0;\n" - "TEMP R1;\n" - "TEX R0, fragment.texcoord[0], texture[0], RECT;\n" - "DP4 R1.w, R0, program.env[%d];\n" - "DP4 R1.z, R0, program.env[%d];\n" - "DP4 R1.x, R0, program.env[%d];\n" - "DP4 R1.y, R0, program.env[%d];\n" - "ADD result.color, R1, program.env[%d];\n" - "END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4); - glGenProgramsARB(1, &s_ColorMatrixProgram); - SetCurrentShader(s_ColorMatrixProgram); - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); - - GLenum err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG(VIDEO, "Failed to create color matrix fragment program"); - glDeleteProgramsARB(1, &s_ColorMatrixProgram); - s_ColorMatrixProgram = 0; - } - - sprintf(pmatrixprog, "!!ARBfp1.0" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "PARAM K0 = { 65535.0, 255.0,1.0,16777215.0};\n" - "PARAM K1 = { 0.999999940395355224609375, 1.0000000596046483281045155587504,0.0,0.0};\n" - "TEX R2, fragment.texcoord[0], texture[0], RECT;\n" - "MUL R0, R2.x, K1.x;\n" - "MUL R0, R0.x, K0;\n" - "FRC R0, R0;\n" - "MUL R0, R0, K1.y;\n" - "DP4 R1.x, R0, program.env[%d];\n" - "DP4 R1.y, R0, program.env[%d];\n" - "DP4 R1.z, R0, program.env[%d];\n" - "DP4 R1.w, R0, program.env[%d];\n" - "ADD result.color, R1, program.env[%d];\n" - "END\n", C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+2, C_COLORMATRIX+3, C_COLORMATRIX+4); - glGenProgramsARB(1, &s_DepthMatrixProgram); - SetCurrentShader(s_DepthMatrixProgram); - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); - - err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG(VIDEO, "Failed to create depth matrix fragment program"); - glDeleteProgramsARB(1, &s_DepthMatrixProgram); - s_DepthMatrixProgram = 0; - } - -} - -PixelShaderCache::~PixelShaderCache() -{ - glDeleteProgramsARB(1, &s_ColorMatrixProgram); - s_ColorMatrixProgram = 0; - glDeleteProgramsARB(1, &s_DepthMatrixProgram); - s_DepthMatrixProgram = 0; - PSCache::iterator iter = pshaders.begin(); - for (; iter != pshaders.end(); iter++) - iter->second.Destroy(); - pshaders.clear(); -} - -GLuint PixelShaderCache::GetColorMatrixProgram() -{ - return s_ColorMatrixProgram; -} - -GLuint PixelShaderCache::GetDepthMatrixProgram() -{ - return s_DepthMatrixProgram; -} - -bool PixelShaderCache::SetShader(bool dstAlphaEnable) -{ - const FRAGMENTSHADER* const ps = GetShader(dstAlphaEnable); - if (ps) - { - SetCurrentShader(ps->glprogid); - return true; - } - else - return false; -} - -FRAGMENTSHADER* PixelShaderCache::GetShader(bool dstAlphaEnable) -{ - DVSTARTPROFILE(); - PIXELSHADERUID uid; - GetPixelShaderId(&uid, dstAlphaEnable ? 1 : 0); - if (uid == last_pixel_shader_uid && pshaders[uid].frameCount == frameCount) - { - return pShaderLast; - } - - memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); - - PSCache::iterator iter = pshaders.find(uid); - - if (iter != pshaders.end()) { - iter->second.frameCount = frameCount; - PSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) - { - pShaderLast = &entry.shader; - } - - return pShaderLast; - } - - //Make an entry in the table - PSCacheEntry& newentry = pshaders[uid]; - newentry.frameCount = frameCount; - pShaderLast = &newentry.shader; - const char *code = GeneratePixelShaderCode(dstAlphaEnable,API_OPENGL); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - - SaveData(szTemp, code); - } -#endif - - // printf("Compiling pixel shader. size = %i\n", strlen(code)); - if (!code || !CompilePixelShader(newentry.shader, code)) { - ERROR_LOG(VIDEO, "failed to create pixel shader"); - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - SaveData(szTemp, code); - return NULL; - } - - INCSTAT(stats.numPixelShadersCreated); - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - return pShaderLast; -} - -bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram) -{ - GLenum err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) - { - ERROR_LOG(VIDEO, "glError %08x before PS!", err); - } - -#if defined HAVE_CG && HAVE_CG - char stropt[128]; - sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions); - const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; - CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts); - - // handle errors - if (!cgIsProgram(tempprog)) { - cgDestroyProgram(tempprog); - ERROR_LOG(VIDEO, "Failed to compile ps %s:", cgGetLastListing(g_cgcontext)); - ERROR_LOG(VIDEO, pstrprogram); - return false; - } - - // handle warnings - if (cgGetError() != CG_NO_ERROR) - { - WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext)); - WARN_LOG(VIDEO, pstrprogram); - } - - // This looks evil - we modify the program through the const char * we got from cgGetProgramString! - // It SHOULD not have any nasty side effects though - but you never know... - char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); - char *plocal = strstr(pcompiledprog, "program.local"); - while (plocal != NULL) { - const char *penv = " program.env"; - memcpy(plocal, penv, 13); - plocal = strstr(plocal+13, "program.local"); - } - - glGenProgramsARB(1, &ps.glprogid); - SetCurrentShader(ps.glprogid); - glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); - - err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) - { - GLint error_pos, native_limit; - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native_limit); - // Error occur - if (error_pos != -1) { - const char *program_error = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB); - char line[256]; - strncpy(line, (const char *)pcompiledprog + error_pos, 255); - line[255] = 0; - ERROR_LOG(VIDEO, "Error at %i: %s", error_pos, program_error); - ERROR_LOG(VIDEO, "Line dump: \n%s", line); - } else if (native_limit != -1) { - ERROR_LOG(VIDEO, "Hit limit? %i", native_limit); - // TODO - } - ERROR_LOG(VIDEO, pstrprogram); - ERROR_LOG(VIDEO, pcompiledprog); - } - - cgDestroyProgram(tempprog); -#endif - -#if defined(_DEBUG) || defined(DEBUGFAST) - ps.strprog = pstrprogram; -#endif - return true; -} - -//Disable Fragment programs and reset the selected Program -void PixelShaderCache::DisableShader() -{ - if(ShaderEnabled) - { - glDisable(GL_FRAGMENT_PROGRAM_ARB); - ShaderEnabled = false; - } -} - - -//bind a program if is diferent from the binded oone -void PixelShaderCache::SetCurrentShader(GLuint Shader) -{ - if(!ShaderEnabled) - { - glEnable(GL_FRAGMENT_PROGRAM_ARB); - ShaderEnabled = true; - } - if(CurrentShader != Shader) - { - if(Shader != 0) - CurrentShader = Shader; - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, CurrentShader); - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +// Common +#include "Common.h" +#include "FileUtil.h" + +// VideoCommon +#include "Profiler.h" +#include "Statistics.h" +#include "VideoConfig.h" +#include "ImageWrite.h" +#include "PixelShaderManager.h" +#include "VertexShaderGen.h" + +// OGL +#include "OGL_Render.h" +#include "OGL_GLUtil.h" +#include "OGL_PixelShaderCache.h" + +#include "../Main.h" + +namespace OGL +{ + +static int s_nMaxPixelInstructions; +static GLuint s_ColorMatrixProgram = 0; +static GLuint s_DepthMatrixProgram = 0; +PixelShaderCache::PSCache PixelShaderCache::pshaders; +PIXELSHADERUID PixelShaderCache::s_curuid; +bool PixelShaderCache::s_displayCompileAlert; +GLuint PixelShaderCache::CurrentShader; +bool PixelShaderCache::ShaderEnabled; + +static FRAGMENTSHADER* pShaderLast = NULL; + + +void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + float f[4] = { f1, f2, f3, f4 }; + glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); + //SetPSConstant4fv(const_number, f); +} + +void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float *f) +{ + glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); +} + +void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) +{ + for (unsigned int i = 0; i < count; ++i, f+=4, ++const_number) + glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f); + //SetPSConstant4fv(const_number, f); +} + +PixelShaderCache::PixelShaderCache() +{ + glEnable(GL_FRAGMENT_PROGRAM_ARB); + ShaderEnabled = true; + CurrentShader = 0; + GL_REPORT_ERRORD(); + + memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid)); + + s_displayCompileAlert = true; + + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions); +#if CG_VERSION_NUM == 2100 + if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL) + { + s_nMaxPixelInstructions = 4096; + } +#endif + + int maxinst, maxattribs; + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&maxinst); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, (GLint *)&maxattribs); + INFO_LOG(VIDEO, "pixel max_alu=%d, max_inst=%d, max_attrib=%d", s_nMaxPixelInstructions, maxinst, maxattribs); + + char pmatrixprog[1024]; + sprintf(pmatrixprog, "!!ARBfp1.0" + "TEMP R0;\n" + "TEMP R1;\n" + "TEX R0, fragment.texcoord[0], texture[0], RECT;\n" + "DP4 R1.w, R0, program.env[%d];\n" + "DP4 R1.z, R0, program.env[%d];\n" + "DP4 R1.x, R0, program.env[%d];\n" + "DP4 R1.y, R0, program.env[%d];\n" + "ADD result.color, R1, program.env[%d];\n" + "END\n", C_COLORMATRIX+3, C_COLORMATRIX+2, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+4); + glGenProgramsARB(1, &s_ColorMatrixProgram); + SetCurrentShader(s_ColorMatrixProgram); + glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); + + GLenum err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG(VIDEO, "Failed to create color matrix fragment program"); + glDeleteProgramsARB(1, &s_ColorMatrixProgram); + s_ColorMatrixProgram = 0; + } + + sprintf(pmatrixprog, "!!ARBfp1.0" + "TEMP R0;\n" + "TEMP R1;\n" + "TEMP R2;\n" + "PARAM K0 = { 65535.0, 255.0,1.0,16777215.0};\n" + "PARAM K1 = { 0.999999940395355224609375, 1.0000000596046483281045155587504,0.0,0.0};\n" + "TEX R2, fragment.texcoord[0], texture[0], RECT;\n" + "MUL R0, R2.x, K1.x;\n" + "MUL R0, R0.x, K0;\n" + "FRC R0, R0;\n" + "MUL R0, R0, K1.y;\n" + "DP4 R1.x, R0, program.env[%d];\n" + "DP4 R1.y, R0, program.env[%d];\n" + "DP4 R1.z, R0, program.env[%d];\n" + "DP4 R1.w, R0, program.env[%d];\n" + "ADD result.color, R1, program.env[%d];\n" + "END\n", C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+2, C_COLORMATRIX+3, C_COLORMATRIX+4); + glGenProgramsARB(1, &s_DepthMatrixProgram); + SetCurrentShader(s_DepthMatrixProgram); + glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pmatrixprog), pmatrixprog); + + err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG(VIDEO, "Failed to create depth matrix fragment program"); + glDeleteProgramsARB(1, &s_DepthMatrixProgram); + s_DepthMatrixProgram = 0; + } + +} + +PixelShaderCache::~PixelShaderCache() +{ + glDeleteProgramsARB(1, &s_ColorMatrixProgram); + s_ColorMatrixProgram = 0; + glDeleteProgramsARB(1, &s_DepthMatrixProgram); + s_DepthMatrixProgram = 0; + PSCache::iterator iter = pshaders.begin(); + for (; iter != pshaders.end(); iter++) + iter->second.Destroy(); + pshaders.clear(); +} + +GLuint PixelShaderCache::GetColorMatrixProgram() +{ + return s_ColorMatrixProgram; +} + +GLuint PixelShaderCache::GetDepthMatrixProgram() +{ + return s_DepthMatrixProgram; +} + +bool PixelShaderCache::SetShader(bool dstAlphaEnable) +{ + const FRAGMENTSHADER* const ps = GetShader(dstAlphaEnable); + if (ps) + { + SetCurrentShader(ps->glprogid); + return true; + } + else + return false; +} + +FRAGMENTSHADER* PixelShaderCache::GetShader(bool dstAlphaEnable) +{ + DVSTARTPROFILE(); + PIXELSHADERUID uid; + GetPixelShaderId(&uid, dstAlphaEnable ? 1 : 0); + if (uid == last_pixel_shader_uid && pshaders[uid].frameCount == frameCount) + { + return pShaderLast; + } + + memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID)); + + PSCache::iterator iter = pshaders.find(uid); + + if (iter != pshaders.end()) { + iter->second.frameCount = frameCount; + PSCacheEntry &entry = iter->second; + if (&entry.shader != pShaderLast) + { + pShaderLast = &entry.shader; + } + + return pShaderLast; + } + + //Make an entry in the table + PSCacheEntry& newentry = pshaders[uid]; + newentry.frameCount = frameCount; + pShaderLast = &newentry.shader; + const char *code = GeneratePixelShaderCode(dstAlphaEnable,API_OPENGL); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + + SaveData(szTemp, code); + } +#endif + + // printf("Compiling pixel shader. size = %i\n", strlen(code)); + if (!code || !CompilePixelShader(newentry.shader, code)) { + ERROR_LOG(VIDEO, "failed to create pixel shader"); + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%sBADps_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + SaveData(szTemp, code); + return NULL; + } + + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); + return pShaderLast; +} + +bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram) +{ + GLenum err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) + { + ERROR_LOG(VIDEO, "glError %08x before PS!", err); + } + +#if defined HAVE_CG && HAVE_CG + char stropt[128]; + sprintf(stropt, "MaxLocalParams=32,NumInstructionSlots=%d", s_nMaxPixelInstructions); + const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; + CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts); + + // handle errors + if (!cgIsProgram(tempprog)) { + cgDestroyProgram(tempprog); + ERROR_LOG(VIDEO, "Failed to compile ps %s:", cgGetLastListing(g_cgcontext)); + ERROR_LOG(VIDEO, pstrprogram); + return false; + } + + // handle warnings + if (cgGetError() != CG_NO_ERROR) + { + WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext)); + WARN_LOG(VIDEO, pstrprogram); + } + + // This looks evil - we modify the program through the const char * we got from cgGetProgramString! + // It SHOULD not have any nasty side effects though - but you never know... + char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); + char *plocal = strstr(pcompiledprog, "program.local"); + while (plocal != NULL) { + const char *penv = " program.env"; + memcpy(plocal, penv, 13); + plocal = strstr(plocal+13, "program.local"); + } + + glGenProgramsARB(1, &ps.glprogid); + SetCurrentShader(ps.glprogid); + glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); + + err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) + { + GLint error_pos, native_limit; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native_limit); + // Error occur + if (error_pos != -1) { + const char *program_error = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB); + char line[256]; + strncpy(line, (const char *)pcompiledprog + error_pos, 255); + line[255] = 0; + ERROR_LOG(VIDEO, "Error at %i: %s", error_pos, program_error); + ERROR_LOG(VIDEO, "Line dump: \n%s", line); + } else if (native_limit != -1) { + ERROR_LOG(VIDEO, "Hit limit? %i", native_limit); + // TODO + } + ERROR_LOG(VIDEO, pstrprogram); + ERROR_LOG(VIDEO, pcompiledprog); + } + + cgDestroyProgram(tempprog); +#endif + +#if defined(_DEBUG) || defined(DEBUGFAST) + ps.strprog = pstrprogram; +#endif + return true; +} + +//Disable Fragment programs and reset the selected Program +void PixelShaderCache::DisableShader() +{ + if(ShaderEnabled) + { + glDisable(GL_FRAGMENT_PROGRAM_ARB); + ShaderEnabled = false; + } +} + + +//bind a program if is diferent from the binded oone +void PixelShaderCache::SetCurrentShader(GLuint Shader) +{ + if(!ShaderEnabled) + { + glEnable(GL_FRAGMENT_PROGRAM_ARB); + ShaderEnabled = true; + } + if(CurrentShader != Shader) + { + if(Shader != 0) + CurrentShader = Shader; + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, CurrentShader); + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.h index 08c532ca33..4c38fcc44f 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PixelShaderCache.h @@ -1,96 +1,96 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_PIXELSHADERCACHE_H_ -#define _OGL_PIXELSHADERCACHE_H_ - -#include -#include - -// VideoCommon -#include "BPMemory.h" -#include "PixelShaderGen.h" - -#include "../PixelShaderCache.h" - -namespace OGL -{ - -struct FRAGMENTSHADER -{ - FRAGMENTSHADER() : glprogid(0) { } - void Destroy() - { - if (glprogid) - { - glDeleteProgramsARB(1, &glprogid); - glprogid = 0; - } - } - GLuint glprogid; // opengl program id -#if defined(_DEBUG) || defined(DEBUGFAST) - std::string strprog; -#endif -}; - -class PixelShaderCache : public ::PixelShaderCacheBase -{ - struct PSCacheEntry - { - FRAGMENTSHADER shader; - int frameCount; - - PSCacheEntry() : frameCount(0) {} - void Destroy() - { - shader.Destroy(); - } - }; - - typedef std::map PSCache; - - static PSCache pshaders; - static PIXELSHADERUID s_curuid; // the current pixel shader uid (progressively changed as memory is written) - static bool s_displayCompileAlert; - static GLuint CurrentShader; - static bool ShaderEnabled; - -public: - PixelShaderCache(); - ~PixelShaderCache(); - - static FRAGMENTSHADER* GetShader(bool dstAlphaEnable); - static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram); - - static GLuint GetColorMatrixProgram(); - static GLuint GetDepthMatrixProgram(); - - bool SetShader(bool dstAlphaEnable); - - static void SetCurrentShader(GLuint Shader); - static void DisableShader(); - - void Clear() {} - - void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetPSConstant4fv(unsigned int const_number, const float *f); - void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f); -}; - -} - -#endif // _PIXELSHADERCACHE_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_PIXELSHADERCACHE_H_ +#define _OGL_PIXELSHADERCACHE_H_ + +#include +#include + +// VideoCommon +#include "BPMemory.h" +#include "PixelShaderGen.h" + +#include "../PixelShaderCache.h" + +namespace OGL +{ + +struct FRAGMENTSHADER +{ + FRAGMENTSHADER() : glprogid(0) { } + void Destroy() + { + if (glprogid) + { + glDeleteProgramsARB(1, &glprogid); + glprogid = 0; + } + } + GLuint glprogid; // opengl program id +#if defined(_DEBUG) || defined(DEBUGFAST) + std::string strprog; +#endif +}; + +class PixelShaderCache : public ::PixelShaderCacheBase +{ + struct PSCacheEntry + { + FRAGMENTSHADER shader; + int frameCount; + + PSCacheEntry() : frameCount(0) {} + void Destroy() + { + shader.Destroy(); + } + }; + + typedef std::map PSCache; + + static PSCache pshaders; + static PIXELSHADERUID s_curuid; // the current pixel shader uid (progressively changed as memory is written) + static bool s_displayCompileAlert; + static GLuint CurrentShader; + static bool ShaderEnabled; + +public: + PixelShaderCache(); + ~PixelShaderCache(); + + static FRAGMENTSHADER* GetShader(bool dstAlphaEnable); + static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram); + + static GLuint GetColorMatrixProgram(); + static GLuint GetDepthMatrixProgram(); + + bool SetShader(bool dstAlphaEnable); + + static void SetCurrentShader(GLuint Shader); + static void DisableShader(); + + void Clear() {} + + void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetPSConstant4fv(unsigned int const_number, const float *f); + void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f); +}; + +} + +#endif // _PIXELSHADERCACHE_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.cpp index ac6661bf49..3ebf0fa662 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.cpp @@ -1,97 +1,97 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Common -#include "FileUtil.h" - -// VideoCommon -#include "VideoCommon.h" -#include "VideoConfig.h" - -// OGL -#include "OGL_GLUtil.h" -#include "OGL_PostProcessing.h" -#include "OGL_PixelShaderCache.h" - -namespace OGL -{ - -namespace PostProcessing -{ - -static std::string s_currentShader; -static FRAGMENTSHADER s_shader; - -void Init() -{ - s_currentShader = ""; -} - -void Shutdown() -{ - s_shader.Destroy(); -} - -void ReloadShader() -{ - s_currentShader = ""; -} - -bool ApplyShader() -{ - if (s_currentShader != std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt") - { - // Set immediately to prevent endless recompiles on failure. - if (!g_ActiveConfig.sPostProcessingShader.empty()) - s_currentShader = std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt"; - else - s_currentShader.clear(); - - s_shader.Destroy(); - - if (!s_currentShader.empty()) - { - std::string code; - if (File::ReadFileToString(true, s_currentShader.c_str(), code)) - { - if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str())) - { - ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); - } - } - else - { - ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str()); - } - } - } - - if (s_shader.glprogid != 0) - { - PixelShaderCache::SetCurrentShader(s_shader.glprogid); - return true; - } - else - { - PixelShaderCache::DisableShader(); - return false; - } -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Common +#include "FileUtil.h" + +// VideoCommon +#include "VideoCommon.h" +#include "VideoConfig.h" + +// OGL +#include "OGL_GLUtil.h" +#include "OGL_PostProcessing.h" +#include "OGL_PixelShaderCache.h" + +namespace OGL +{ + +namespace PostProcessing +{ + +static std::string s_currentShader; +static FRAGMENTSHADER s_shader; + +void Init() +{ + s_currentShader = ""; +} + +void Shutdown() +{ + s_shader.Destroy(); +} + +void ReloadShader() +{ + s_currentShader = ""; +} + +bool ApplyShader() +{ + if (s_currentShader != std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt") + { + // Set immediately to prevent endless recompiles on failure. + if (!g_ActiveConfig.sPostProcessingShader.empty()) + s_currentShader = std::string(File::GetUserPath(D_SHADERS_IDX)) + g_ActiveConfig.sPostProcessingShader + ".txt"; + else + s_currentShader.clear(); + + s_shader.Destroy(); + + if (!s_currentShader.empty()) + { + std::string code; + if (File::ReadFileToString(true, s_currentShader.c_str(), code)) + { + if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str())) + { + ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str()); + } + } + else + { + ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str()); + } + } + } + + if (s_shader.glprogid != 0) + { + PixelShaderCache::SetCurrentShader(s_shader.glprogid); + return true; + } + else + { + PixelShaderCache::DisableShader(); + return false; + } +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.h index 6bd680c4ad..c6b7f272cc 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_PostProcessing.h @@ -1,42 +1,42 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_POSTPROCESSING_H_ -#define _OGL_POSTPROCESSING_H_ - -#include "VideoCommon.h" - -#include "OGL_GLUtil.h" - -namespace OGL -{ - -namespace PostProcessing -{ - -void Init(); -void Shutdown(); - -void ReloadShader(); -// Returns false if no shader was applied. -bool ApplyShader(); - -} // namespace - -} - -#endif // _POSTPROCESSING_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_POSTPROCESSING_H_ +#define _OGL_POSTPROCESSING_H_ + +#include "VideoCommon.h" + +#include "OGL_GLUtil.h" + +namespace OGL +{ + +namespace PostProcessing +{ + +void Init(); +void Shutdown(); + +void ReloadShader(); +// Returns false if no shader was applied. +bool ApplyShader(); + +} // namespace + +} + +#endif // _POSTPROCESSING_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.cpp index d1d9bb7b42..97f659b0bd 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.cpp @@ -1,226 +1,226 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -#include "OGL_GLUtil.h" -#include "OGL_RasterFont.h" -// globals - -namespace OGL -{ - -GLubyte rasters[][13] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, - {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, - {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, - {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, - {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, - {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, - {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, - {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, - {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, - {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, - {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, - {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, - {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, - {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, - {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, - {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, - {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, - {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, - {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, - {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, - {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, - {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, - {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, - {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, - {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, - {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, - {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, - {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, - {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, - {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, - {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, - {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, - {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} -}; - -RasterFont::RasterFont() -{ - // set GL modes - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // create the raster font - fontOffset = glGenLists(128); - for (int i = 32; i < 127; i++) { - glNewList(i + fontOffset, GL_COMPILE); - glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i - 32]); - glEndList(); - } - - temp_buffer = new char[TEMP_BUFFER_SIZE]; -} - -RasterFont::~RasterFont() -{ - glDeleteLists(fontOffset, 128); - delete [] temp_buffer; -} - -void RasterFont::printString(const char *s, double x, double y, double z) -{ - int length = (int)strlen(s); - if (!length) - return; - if (length >= TEMP_BUFFER_SIZE) - length = TEMP_BUFFER_SIZE - 1; - - // Sanitize string to avoid GL errors. - char *s2 = temp_buffer; - memcpy(s2, s, length); - s2[length] = 0; - for (int i = 0; i < length; i++) - if (s2[i] < 32 || s2[i] > 126) - s2[i] = '!'; - - // go to the right spot - glRasterPos3d(x, y, z); - GL_REPORT_ERRORD(); - - glPushAttrib (GL_LIST_BIT); - glListBase(fontOffset); - glCallLists((GLsizei)strlen(s2), GL_UNSIGNED_BYTE, (GLubyte *) s2); - GL_REPORT_ERRORD(); - glPopAttrib(); - GL_REPORT_ERRORD(); -} - -void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) -{ - int length = (int)strlen(s); - int x = (int)(screen_width/2.0 - (length/2.0)*char_width); - printString(s, x, y, z); -} - -void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight) -{ - double x = start_x; - double y = start_y; - char temp[1024]; - char *t = temp; - while (*text) - { - if (*text == '\n') - { - *t = 0; - printString(temp, x, y, z); - y -= char_height * 2.0f / bbHeight; - x = start_x; - t = temp; - } - else if (*text == '\r') - { - t = temp; - } - else if (*text == '\t') - { - //todo: add tabs every something like 4*char_width - *t = 0; - int cpos = (int)strlen(temp); - int newpos = (cpos + 4) & (~3); - printString(temp, x, y, z); - x = start_x + (char_width*newpos) * 2.0f / bbWidth; - t = temp; - *t++ = ' '; - } - else - *t++ = *text; - - text++; - } - - // ???? - if (t != text) - { - *t = 0; - printString(temp, x, y, z); - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +#include "OGL_GLUtil.h" +#include "OGL_RasterFont.h" +// globals + +namespace OGL +{ + +GLubyte rasters[][13] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, + {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, + {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, + {0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, + {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, + {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, + {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, + {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, + {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, + {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, + {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, + {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, + {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, + {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, + {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, + {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, + {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, + {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, + {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, + {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, + {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, + {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, + {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, + {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, + {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, + {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, + {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, + {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, + {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, + {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} +}; + +RasterFont::RasterFont() +{ + // set GL modes + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // create the raster font + fontOffset = glGenLists(128); + for (int i = 32; i < 127; i++) { + glNewList(i + fontOffset, GL_COMPILE); + glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i - 32]); + glEndList(); + } + + temp_buffer = new char[TEMP_BUFFER_SIZE]; +} + +RasterFont::~RasterFont() +{ + glDeleteLists(fontOffset, 128); + delete [] temp_buffer; +} + +void RasterFont::printString(const char *s, double x, double y, double z) +{ + int length = (int)strlen(s); + if (!length) + return; + if (length >= TEMP_BUFFER_SIZE) + length = TEMP_BUFFER_SIZE - 1; + + // Sanitize string to avoid GL errors. + char *s2 = temp_buffer; + memcpy(s2, s, length); + s2[length] = 0; + for (int i = 0; i < length; i++) + if (s2[i] < 32 || s2[i] > 126) + s2[i] = '!'; + + // go to the right spot + glRasterPos3d(x, y, z); + GL_REPORT_ERRORD(); + + glPushAttrib (GL_LIST_BIT); + glListBase(fontOffset); + glCallLists((GLsizei)strlen(s2), GL_UNSIGNED_BYTE, (GLubyte *) s2); + GL_REPORT_ERRORD(); + glPopAttrib(); + GL_REPORT_ERRORD(); +} + +void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z) +{ + int length = (int)strlen(s); + int x = (int)(screen_width/2.0 - (length/2.0)*char_width); + printString(s, x, y, z); +} + +void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight) +{ + double x = start_x; + double y = start_y; + char temp[1024]; + char *t = temp; + while (*text) + { + if (*text == '\n') + { + *t = 0; + printString(temp, x, y, z); + y -= char_height * 2.0f / bbHeight; + x = start_x; + t = temp; + } + else if (*text == '\r') + { + t = temp; + } + else if (*text == '\t') + { + //todo: add tabs every something like 4*char_width + *t = 0; + int cpos = (int)strlen(temp); + int newpos = (cpos + 4) & (~3); + printString(temp, x, y, z); + x = start_x + (char_width*newpos) * 2.0f / bbWidth; + t = temp; + *t++ = ' '; + } + else + *t++ = *text; + + text++; + } + + // ???? + if (t != text) + { + *t = 0; + printString(temp, x, y, z); + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.h index 73d4dbf13e..c47d1b4d15 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_RasterFont.h @@ -1,51 +1,51 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_RASTERFONT_H_ -#define _OGL_RASTERFONT_H_ - -namespace OGL -{ - -class RasterFont { -public: - RasterFont(); - ~RasterFont(void); - static int debug; - - // some useful constants - enum - { - char_width = 10, - char_height = 15, - }; - - // and the happy helper functions - void printString(const char *s, double x, double y, double z=0.0); - void printCenteredString(const char *s, double y, int screen_width, double z=0.0); - - void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight); - -private: - int fontOffset; - char *temp_buffer; - enum {TEMP_BUFFER_SIZE = 64 * 1024}; -}; - -} - -#endif // _RASTERFONT_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_RASTERFONT_H_ +#define _OGL_RASTERFONT_H_ + +namespace OGL +{ + +class RasterFont { +public: + RasterFont(); + ~RasterFont(void); + static int debug; + + // some useful constants + enum + { + char_width = 10, + char_height = 15, + }; + + // and the happy helper functions + void printString(const char *s, double x, double y, double z=0.0); + void printCenteredString(const char *s, double y, int screen_width, double z=0.0); + + void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight); + +private: + int fontOffset; + char *temp_buffer; + enum {TEMP_BUFFER_SIZE = 64 * 1024}; +}; + +} + +#endif // _RASTERFONT_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp index 0ece6694f3..0801c1b757 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp @@ -1,985 +1,985 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - - -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef _WIN32 -//#include "OS/Win32.h" -//#include "AVIDump.h" - -#include -#endif - -#if defined(HAVE_WX) && HAVE_WX -#include -#endif - -// Common -#include "Thread.h" -#include "Atomic.h" -#include "FileUtil.h" -#include "CommonPaths.h" -#include "Timer.h" -#include "StringUtil.h" - -// VideoCommon -#include "VideoConfig.h" -#include "Profiler.h" -#include "Statistics.h" -#include "ImageWrite.h" -#include "OpcodeDecoding.h" -#include "BPStructs.h" -#include "VertexShaderGen.h" -#include "DLCache.h" -#include "PixelShaderManager.h" -#include "VertexShaderManager.h" -#include "VertexLoaderManager.h" -#include "VertexLoader.h" -#include "OnScreenDisplay.h" -#include "Fifo.h" - -// OGL -#include "OGL_GLUtil.h" -#include "OGL_TextureCache.h" -#include "OGL_RasterFont.h" -#include "OGL_PixelShaderCache.h" -#include "OGL_VertexShaderCache.h" -#include "OGL_PostProcessing.h" -#include "OGL_TextureConverter.h" -#include "OGL_FramebufferManager.h" -#include "OGL_XFB.h" -#include "OGL_Render.h" - -#include "../Main.h" - -namespace OGL -{ - -// Declarations and definitions -// ---------------------------- - -#if defined HAVE_CG && HAVE_CG -CGcontext g_cgcontext; -CGprofile g_cgvProf; -CGprofile g_cgfProf; -#endif - -RasterFont* s_pfont = NULL; - -static bool s_bLastFrameDumped = false; -#ifdef _WIN32 -static bool s_bAVIDumping = false; -#else -static FILE* f_pFrameDump; -#endif - -// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. -static int s_MSAASamples = 1; -static int s_MSAACoverageSamples = 0; - -bool s_bHaveFramebufferBlit = false; // export to FramebufferManager.cpp -static bool s_bHaveCoverageMSAA = false; - -// The custom resolution - -static bool s_skipSwap = false; - -// TODO: EmuWindow has these too, merge them -int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; - -#if defined(HAVE_WX) && HAVE_WX -// Screenshot thread struct -typedef struct -{ - int W, H; - std::string filename; - wxImage *img; -} ScrStrct; -#endif - -static const GLenum glSrcFactors[8] = -{ - GL_ZERO, - GL_ONE, - GL_DST_COLOR, - GL_ONE_MINUS_DST_COLOR, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_DST_ALPHA, - GL_ONE_MINUS_DST_ALPHA -}; - -static const GLenum glDestFactors[8] = { - GL_ZERO, - GL_ONE, - GL_SRC_COLOR, - GL_ONE_MINUS_SRC_COLOR, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_DST_ALPHA, - GL_ONE_MINUS_DST_ALPHA -}; - -static const GLenum glCmpFuncs[8] = { - GL_NEVER, - GL_LESS, - GL_EQUAL, - GL_LEQUAL, - GL_GREATER, - GL_NOTEQUAL, - GL_GEQUAL, - GL_ALWAYS -}; - -static const GLenum glLogicOpCodes[16] = { - GL_CLEAR, - GL_AND, - GL_AND_REVERSE, - GL_COPY, - GL_AND_INVERTED, - GL_NOOP, - GL_XOR, - GL_OR, - GL_NOR, - GL_EQUIV, - GL_INVERT, - GL_OR_REVERSE, - GL_COPY_INVERTED, - GL_OR_INVERTED, - GL_NAND, - GL_SET -}; - -#if defined HAVE_CG && HAVE_CG -void HandleCgError(CGcontext ctx, CGerror err, void* appdata) -{ - DEBUG_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err)); - const char* listing = cgGetLastListing(g_cgcontext); - if (listing != NULL) - DEBUG_LOG(VIDEO, " last listing: %s", listing); -} -#endif - -// Init functions -Renderer::Renderer() -{ - // hmm - if (!OpenGL_Create(g_VideoInitialize, 640, 480)) - { - g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE); - return; - } - - OpenGL_MakeCurrent(); - - //if (!Renderer::Init()) { - // g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE); - // PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info"); - // exit(1); - //} - - bool bSuccess = true; - s_MSAACoverageSamples = 0; - GLint numvertexattribs = 0; - - switch (g_ActiveConfig.iMultisampleMode) - { - case MULTISAMPLE_OFF: - s_MSAASamples = 1; - break; - - case MULTISAMPLE_2X: - s_MSAASamples = 2; - break; - - case MULTISAMPLE_4X: - s_MSAASamples = 4; - break; - - case MULTISAMPLE_8X: - s_MSAASamples = 8; - break; - - case MULTISAMPLE_CSAA_8X: - s_MSAASamples = 4; s_MSAACoverageSamples = 8; - break; - - case MULTISAMPLE_CSAA_8XQ: - s_MSAASamples = 8; s_MSAACoverageSamples = 8; - break; - - case MULTISAMPLE_CSAA_16X: - s_MSAASamples = 4; s_MSAACoverageSamples = 16; - break; - - case MULTISAMPLE_CSAA_16XQ: - s_MSAASamples = 8; s_MSAACoverageSamples = 16; - break; - - default: - s_MSAASamples = 1; - break; - } - -#if defined HAVE_CG && HAVE_CG - g_cgcontext = cgCreateContext(); - cgGetError(); - cgSetErrorHandler(HandleCgError, NULL); -#endif - - // Look for required extensions. - const char *const ptoken = (const char*)glGetString(GL_EXTENSIONS); - if (!ptoken) - { - PanicAlert("Your OpenGL Driver seems to be not working.\n" - "Please make sure your drivers are up-to-date and\n" - "that your video hardware is OpenGL 2.x compatible."); - //return false; - return; - } - - INFO_LOG(VIDEO, "Supported OpenGL Extensions:"); - INFO_LOG(VIDEO, ptoken); // write to the log file - INFO_LOG(VIDEO, ""); - - OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", - glGetString(GL_VENDOR), - glGetString(GL_RENDERER), - glGetString(GL_VERSION)).c_str(), 5000); - - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs); - if (numvertexattribs < 11) - { - ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n" - "GPU: Does your video card support OpenGL 2.x?", - numvertexattribs); - bSuccess = false; - } - - // Init extension support. - if (glewInit() != GLEW_OK) - { - ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?"); - //return false; - - return; - } - - if (!GLEW_EXT_framebuffer_object) - { - ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets.\n" - "GPU: Does your video card support OpenGL 2.x?"); - bSuccess = false; - } - - if (!GLEW_EXT_secondary_color) - { - ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" - "GPU: Does your video card support OpenGL 2.x?"); - bSuccess = false; - } - - s_bHaveFramebufferBlit = strstr(ptoken, "GL_EXT_framebuffer_blit") != NULL; - if (!s_bHaveFramebufferBlit) - { - // MSAA ain't gonna work. turn it off if enabled. - s_MSAASamples = 1; - } - - s_bHaveCoverageMSAA = strstr(ptoken, "GL_NV_framebuffer_multisample_coverage") != NULL; - if (!s_bHaveCoverageMSAA) - { - s_MSAACoverageSamples = 0; - } - - if (!bSuccess) - //return false; - return; - - // Handle VSync on/off -#if defined USE_WX && USE_WX - // TODO: FILL IN -#elif defined _WIN32 - if (WGLEW_EXT_swap_control) - wglSwapIntervalEXT(g_ActiveConfig.bVSync ? 1 : 0); - else - ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); -#elif defined(HAVE_X11) && HAVE_X11 - if (glXSwapIntervalSGI) - glXSwapIntervalSGI(g_ActiveConfig.bVSync ? 1 : 0); - else - ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); -#endif - - // check the max texture width and height - GLint max_texture_size; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size); - if (max_texture_size < 1024) - ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.", - max_texture_size); - - if (GL_REPORT_ERROR() != GL_NO_ERROR) - bSuccess = false; - - if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers) - glDrawBuffers = glDrawBuffersARB; - - if (!GLEW_ARB_texture_non_power_of_two) - WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported."); - - // Decide frambuffer size - FramebufferSize((int)OpenGL_GetBackbufferWidth(), (int)OpenGL_GetBackbufferHeight()); - - // Because of the fixed framebuffer size we need to disable the resolution - // options while running - g_Config.bRunning = true; - - if (GL_REPORT_ERROR() != GL_NO_ERROR) - bSuccess = false; - - // Initialize the FramebufferManager - g_framebuffer_manager = new FramebufferManager(s_backbuffer_width, - s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples); - - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - - if (GL_REPORT_ERROR() != GL_NO_ERROR) - bSuccess = false; - - s_pfont = new RasterFont(); - -#if defined HAVE_CG && HAVE_CG - // load the effect, find the best profiles (if any) - if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE) - { - ERROR_LOG(VIDEO, "arbvp1 not supported"); - return false; - } - - if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE) - { - ERROR_LOG(VIDEO, "arbfp1 not supported"); - return false; - } - - g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX); - g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); -#if CG_VERSION_NUM == 2100 - // A bug was introduced in Cg2.1's handling of very large profile option values - // so this will not work on ATI. ATI returns MAXINT = 2147483647 (0x7fffffff) - // which is correct in OpenGL but Cg fails to handle it properly. As a result - // -1 is used by Cg resulting (signedness incorrect) and compilation fails. - if (strstr((const char*)glGetString(GL_VENDOR), "ATI") == NULL) -#endif - { - cgGLSetOptimalOptions(g_cgvProf); - cgGLSetOptimalOptions(g_cgfProf); - } -#endif // HAVE_CG - - int nenvvertparams, nenvfragparams, naddrregisters[2]; - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, - GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, - (GLint *)&nenvvertparams); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, - GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, - (GLint *)&nenvfragparams); - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, - GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, - (GLint *)&naddrregisters[0]); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, - GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, - (GLint *)&naddrregisters[1]); - DEBUG_LOG(VIDEO, "Max program env parameters: vert=%d, frag=%d", - nenvvertparams, nenvfragparams); - DEBUG_LOG(VIDEO, "Max program address register parameters: vert=%d, frag=%d", - naddrregisters[0], naddrregisters[1]); - - if (nenvvertparams < 238) - ERROR_LOG(VIDEO, "Not enough vertex shader environment constants!!"); - -#if defined HAVE_CG && HAVE_CG - INFO_LOG(VIDEO, "Max buffer sizes: %d %d", - cgGetProgramBufferMaxSize(g_cgvProf), - cgGetProgramBufferMaxSize(g_cgfProf)); -#ifndef _DEBUG - cgGLSetDebugMode(GL_FALSE); -#endif -#endif - - glStencilFunc(GL_ALWAYS, 0, 0); - glBlendFunc(GL_ONE, GL_ONE); - - glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glShadeModel(GL_SMOOTH); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDepthFunc(GL_LEQUAL); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment - - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - - glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); - glBlendColorEXT(0, 0, 0, 0.5f); - glClearDepth(1.0f); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // legacy multitexturing: select texture channel only. - glActiveTexture(GL_TEXTURE0); - glClientActiveTexture(GL_TEXTURE0); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - UpdateActiveConfig(); - //return GL_REPORT_ERROR() == GL_NO_ERROR && bSuccess; - - return; -} - -Renderer::~Renderer() -{ - g_Config.bRunning = false; - UpdateActiveConfig(); - delete s_pfont; - s_pfont = 0; - -#if defined HAVE_CG && HAVE_CG - if (g_cgcontext) - { - cgDestroyContext(g_cgcontext); - g_cgcontext = 0; - } -#endif - - delete g_framebuffer_manager; - -//#ifdef _WIN32 -// if(s_bAVIDumping) -// AVIDump::Stop(); -//#else -// if(f_pFrameDump != NULL) -// fclose(f_pFrameDump); -//#endif - - OpenGL_Shutdown(); -} - -// For the OSD menu's live resolution change -bool Renderer::Allow2x() -{ - if (GetFrameBufferWidth() >= 1280 && GetFrameBufferHeight() >= 960) - return true; - else - return false; -} - -bool Renderer::AllowCustom() -{ - //if (GetCustomWidth() <= GetFrameBufferWidth() && GetCustomHeight() <= GetFrameBufferHeight()) - // return true; - //else - // return false; - - return false; -} - -void Renderer::ResetAPIState() -{ - // Gets us to a reasonably sane state where it's possible to do things like - // image copies with textured quads, etc. - VertexShaderCache::DisableShader(); - PixelShaderCache::DisableShader(); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -} - -void UpdateViewport(); - -void Renderer::RestoreAPIState() -{ - // Gets us back into a more game-like state. - - UpdateViewport(); - - if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE); - if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); - if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); - - glEnable(GL_SCISSOR_TEST); - SetScissorRect(); - SetColorMask(); - SetBlendMode(true); - - VertexShaderCache::SetCurrentShader(0); - PixelShaderCache::SetCurrentShader(0); -} - -void Renderer::SetColorMask() -{ - GLenum ColorMask = (bpmem.blendmode.colorupdate) ? GL_TRUE : GL_FALSE; - GLenum AlphaMask = (bpmem.blendmode.alphaupdate) ? GL_TRUE : GL_FALSE; - glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); -} - -void Renderer::SetBlendMode(bool forceUpdate) -{ - // blend mode bit mask - // 0 - blend enable - // 2 - reverse subtract enable (else add) - // 3-5 - srcRGB function - // 6-8 - dstRGB function - - u32 newval = bpmem.blendmode.subtract << 2; - - if (bpmem.blendmode.subtract) - newval |= 0x0049; // enable blending src 1 dst 1 - else if (bpmem.blendmode.blendenable) - { - newval |= 1; // enable blending - newval |= bpmem.blendmode.srcfactor << 3; - newval |= bpmem.blendmode.dstfactor << 6; - } - - u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; - - if (changes & 1) - // blend enable change - (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); - - if (changes & 4) - // subtract enable change - glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD); - - if (changes & 0x1F8) - // blend RGB change - glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); - - s_blendMode = newval; -} - -u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) -{ - if(!g_ActiveConfig.bEFBAccessEnable) - return 0; - - // Get the rectangular target region covered by the EFB pixel. - EFBRectangle efbPixelRc; - efbPixelRc.left = x; - efbPixelRc.top = y; - efbPixelRc.right = x + 1; - efbPixelRc.bottom = y + 1; - - TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); - - // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel - switch (type) - { - - case PEEK_Z: - { - if (s_MSAASamples > 1) - { - // Resolve our rectangle. - FramebufferManager::GetEFBDepthTexture(efbPixelRc); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer()); - } - - // Sample from the center of the target region. - int srcX = (targetPixelRc.left + targetPixelRc.right) / 2; - int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2; - - u32 z = 0; - glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z); - GL_REPORT_ERRORD(); - - // Scale the 32-bit value returned by glReadPixels to a 24-bit - // value (GC uses a 24-bit Z-buffer). - // TODO: in RE0 this value is often off by one, which causes lighting to disappear - return z >> 8; - } - - case POKE_Z: - // TODO: Implement - break; - - case PEEK_COLOR: // GXPeekARGB - { - // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit... - - // Tested in Killer 7, the first 8bits represent the alpha value which is used to - // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70) - // Wind Waker is also using it for the pictograph to determine the color of each pixel - - if (s_MSAASamples > 1) - { - // Resolve our rectangle. - FramebufferManager::GetEFBColorTexture(efbPixelRc); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer()); - } - - // Sample from the center of the target region. - int srcX = (targetPixelRc.left + targetPixelRc.right) / 2; - int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2; - - // Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format. - u32 color = 0; - glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color); - GL_REPORT_ERRORD(); - - return color; - } - - case POKE_COLOR: - // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at - // the exact location. Note: EFB pokes are susceptible to Z-buffering - // and perhaps blending. - //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering"); - break; - - } - - return 0; -} - -// Function: This function handles the OpenGL glScissor() function -// ---------------------------- -// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() -// case 0x52 > SetScissorRect() -// ---------------------------- -// bpmem.scissorTL.x, y = 342x342 -// bpmem.scissorBR.x, y = 981x821 -// GetTargetHeight() = the fixed ini file setting -// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box -// therefore the width and height are (scissorBR + 1) - scissorTL -bool Renderer::SetScissorRect() -{ - EFBRectangle rc; - if (g_renderer->SetScissorRect(rc)) - { - glScissor( - (int)(rc.left * EFBxScale), // x = 0 for example - (int)((EFB_HEIGHT - rc.bottom) * EFByScale), // y = 0 for example - (int)((rc.right - rc.left) * EFBxScale), // width = 640 for example - (int)((rc.bottom - rc.top) * EFByScale) // height = 480 for example - ); - return true; - } - else - { - glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); - } - return false; -} - -void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, - bool alphaEnable, bool zEnable, u32 color, u32 z) -{ - // Update the view port for clearing the picture - TargetRectangle targetRc = ConvertEFBRectangle(rc); - glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); - glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); - - // Always set the scissor in case it was set by the game and has not been reset - - VertexShaderManager::SetViewportChanged(); - - GLbitfield bits = 0; - if (colorEnable) - { - bits |= GL_COLOR_BUFFER_BIT; - glClearColor( - ((color >> 16) & 0xFF) / 255.0f, - ((color >> 8) & 0xFF) / 255.0f, - (color & 0xFF) / 255.0f, - ((color >> 24) & 0xFF) / 255.0f - ); - } - if (zEnable) - { - bits |= GL_DEPTH_BUFFER_BIT; - glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF)); - } - - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glClear(bits); - SetScissorRect(); -} - -void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect) -{ - // Update GLViewPort - glViewport(dst_rect.left, dst_rect.bottom, dst_rect.GetWidth(), dst_rect.GetHeight()); - - GL_REPORT_ERRORD(); - - // Copy the framebuffer to screen. - - // Texture map s_xfbTexture onto the main buffer - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - // Use linear filtering. - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) -{ - // testing - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - if (xfbSource) - { - // Texture map xfbSource->texture onto the main buffer - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ((XFBSource*)xfbSource)->texture); - } - else - { - // Render to the real buffer now. - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, FramebufferManager::ResolveAndGetRenderTarget(rc)); - } - - // We must call ApplyShader here even if no post proc is selected - it takes - // care of disabling it in that case. It returns false in case of no post processing. - bool applyShader = PostProcessing::ApplyShader(); - if (applyShader) - { - glBegin(GL_QUADS); - glTexCoord2f(sourceRc.left, sourceRc.bottom); - glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); - glVertex2f(drawRc.left, drawRc.bottom); - - glTexCoord2f(sourceRc.left, sourceRc.top); - glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); - glVertex2f(drawRc.left, drawRc.top); - - glTexCoord2f(sourceRc.right, sourceRc.top); - glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); - glVertex2f(drawRc.right, drawRc.top); - - glTexCoord2f(sourceRc.right, sourceRc.bottom); - glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); - glVertex2f(drawRc.right, drawRc.bottom); - glEnd(); - PixelShaderCache::DisableShader(); - } - else - { - glBegin(GL_QUADS); - glTexCoord2f(sourceRc.left, sourceRc.bottom); - glVertex2f(drawRc.left, drawRc.bottom); - - glTexCoord2f(sourceRc.left, sourceRc.top); - glVertex2f(drawRc.left, drawRc.top); - - glTexCoord2f(sourceRc.right, sourceRc.top); - glVertex2f(drawRc.right, drawRc.top); - - glTexCoord2f(sourceRc.right, sourceRc.bottom); - glVertex2f(drawRc.right, drawRc.bottom); - glEnd(); - } - - GL_REPORT_ERRORD(); - - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureCache::DisableStage(0); - - // TODO: silly place for this - // Wireframe - if (g_ActiveConfig.bWireFrame) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -} - -void Renderer::EndFrame() -{ - // Copy the rendered frame to the real window - OpenGL_SwapBuffers(); - - GL_REPORT_ERRORD(); - - // Clear framebuffer - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - GL_REPORT_ERRORD(); -} - -void Renderer::Present() -{ - // Render to the framebuffer. - FramebufferManager::SetFramebuffer(0); - - GL_REPORT_ERRORD(); -} - -bool Renderer::CheckForResize() -{ - // TODO: temp - - OpenGL_Update(); // just updates the render window position and the backbuffer size - return true; -} - -void Renderer::GetBackBufferSize(int* w, int* h) -{ - *w = (int)OpenGL_GetBackbufferWidth(); - *h = (int)OpenGL_GetBackbufferHeight(); -} - -void Renderer::RecreateFramebufferManger() -{ - delete g_framebuffer_manager; - g_framebuffer_manager = new FramebufferManager(s_backbuffer_width, - s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples); - - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); -} - -void Renderer::BeginFrame() -{ - // TODO: silly place for this - g_Config.iSaveTargetId = 0; - - bool last_copy_efb_to_Texture = g_ActiveConfig.bCopyEFBToTexture; - UpdateActiveConfig(); - if (last_copy_efb_to_Texture != g_ActiveConfig.bCopyEFBToTexture) - TextureCache::ClearRenderTargets(); -} - -// Called from VertexShaderManager -void Renderer::UpdateViewport() -{ - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz - float scissorXOff = float(bpmem.scissorOffset.x) * 2.0f; // 342 - float scissorYOff = float(bpmem.scissorOffset.y) * 2.0f; // 342 - - // Stretch picture with increased internal resolution - int GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - scissorXOff) * - EFBxScale); - int GLy = (int)ceil( - (float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + scissorYOff) * - EFByScale); - int GLWidth = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale); - int GLHeight = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale); - double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f; - double GLFar = xfregs.rawViewport[5] / 16777216.0f; - if(GLWidth < 0) - { - GLx += GLWidth; - GLWidth*=-1; - } - if(GLHeight < 0) - { - GLy += GLHeight; - GLHeight *= -1; - } - // Update the view port - glViewport(GLx, GLy, GLWidth, GLHeight); - glDepthRange(GLNear, GLFar); -} - -void Renderer::SetGenerationMode() -{ - // none, ccw, cw, ccw - if (bpmem.genMode.cullmode > 0) - { - glEnable(GL_CULL_FACE); - glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); - } - else - glDisable(GL_CULL_FACE); -} - -void Renderer::SetDepthMode() -{ - if (bpmem.zmode.testenable) - { - glEnable(GL_DEPTH_TEST); - glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); - glDepthFunc(glCmpFuncs[bpmem.zmode.func]); - } - else - { - // if the test is disabled write is disabled too - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - } -} - -void Renderer::SetLogicOpMode() -{ - if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) - { - glEnable(GL_COLOR_LOGIC_OP); - glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); - } - else - glDisable(GL_COLOR_LOGIC_OP); -} - -void Renderer::SetDitherMode() -{ - if (bpmem.blendmode.dither) - glEnable(GL_DITHER); - else - glDisable(GL_DITHER); -} - -void Renderer::SetLineWidth() -{ - float fratio = xfregs.rawViewport[0] != 0 ? - ((float)GetTargetWidth() / EFB_WIDTH) : 1.0f; - if (bpmem.lineptwidth.linesize > 0) - // scale by ratio of widths - glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); - if (bpmem.lineptwidth.pointsize > 0) - glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 +//#include "OS/Win32.h" +//#include "AVIDump.h" + +#include +#endif + +#if defined(HAVE_WX) && HAVE_WX +#include +#endif + +// Common +#include "Thread.h" +#include "Atomic.h" +#include "FileUtil.h" +#include "CommonPaths.h" +#include "Timer.h" +#include "StringUtil.h" + +// VideoCommon +#include "VideoConfig.h" +#include "Profiler.h" +#include "Statistics.h" +#include "ImageWrite.h" +#include "OpcodeDecoding.h" +#include "BPStructs.h" +#include "VertexShaderGen.h" +#include "DLCache.h" +#include "PixelShaderManager.h" +#include "VertexShaderManager.h" +#include "VertexLoaderManager.h" +#include "VertexLoader.h" +#include "OnScreenDisplay.h" +#include "Fifo.h" + +// OGL +#include "OGL_GLUtil.h" +#include "OGL_TextureCache.h" +#include "OGL_RasterFont.h" +#include "OGL_PixelShaderCache.h" +#include "OGL_VertexShaderCache.h" +#include "OGL_PostProcessing.h" +#include "OGL_TextureConverter.h" +#include "OGL_FramebufferManager.h" +#include "OGL_XFB.h" +#include "OGL_Render.h" + +#include "../Main.h" + +namespace OGL +{ + +// Declarations and definitions +// ---------------------------- + +#if defined HAVE_CG && HAVE_CG +CGcontext g_cgcontext; +CGprofile g_cgvProf; +CGprofile g_cgfProf; +#endif + +RasterFont* s_pfont = NULL; + +static bool s_bLastFrameDumped = false; +#ifdef _WIN32 +static bool s_bAVIDumping = false; +#else +static FILE* f_pFrameDump; +#endif + +// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. +static int s_MSAASamples = 1; +static int s_MSAACoverageSamples = 0; + +bool s_bHaveFramebufferBlit = false; // export to FramebufferManager.cpp +static bool s_bHaveCoverageMSAA = false; + +// The custom resolution + +static bool s_skipSwap = false; + +// TODO: EmuWindow has these too, merge them +int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; + +#if defined(HAVE_WX) && HAVE_WX +// Screenshot thread struct +typedef struct +{ + int W, H; + std::string filename; + wxImage *img; +} ScrStrct; +#endif + +static const GLenum glSrcFactors[8] = +{ + GL_ZERO, + GL_ONE, + GL_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA +}; + +static const GLenum glDestFactors[8] = { + GL_ZERO, + GL_ONE, + GL_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA +}; + +static const GLenum glCmpFuncs[8] = { + GL_NEVER, + GL_LESS, + GL_EQUAL, + GL_LEQUAL, + GL_GREATER, + GL_NOTEQUAL, + GL_GEQUAL, + GL_ALWAYS +}; + +static const GLenum glLogicOpCodes[16] = { + GL_CLEAR, + GL_AND, + GL_AND_REVERSE, + GL_COPY, + GL_AND_INVERTED, + GL_NOOP, + GL_XOR, + GL_OR, + GL_NOR, + GL_EQUIV, + GL_INVERT, + GL_OR_REVERSE, + GL_COPY_INVERTED, + GL_OR_INVERTED, + GL_NAND, + GL_SET +}; + +#if defined HAVE_CG && HAVE_CG +void HandleCgError(CGcontext ctx, CGerror err, void* appdata) +{ + DEBUG_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err)); + const char* listing = cgGetLastListing(g_cgcontext); + if (listing != NULL) + DEBUG_LOG(VIDEO, " last listing: %s", listing); +} +#endif + +// Init functions +Renderer::Renderer() +{ + // hmm + if (!OpenGL_Create(g_VideoInitialize, 640, 480)) + { + g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE); + return; + } + + OpenGL_MakeCurrent(); + + //if (!Renderer::Init()) { + // g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE); + // PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info"); + // exit(1); + //} + + bool bSuccess = true; + s_MSAACoverageSamples = 0; + GLint numvertexattribs = 0; + + switch (g_ActiveConfig.iMultisampleMode) + { + case MULTISAMPLE_OFF: + s_MSAASamples = 1; + break; + + case MULTISAMPLE_2X: + s_MSAASamples = 2; + break; + + case MULTISAMPLE_4X: + s_MSAASamples = 4; + break; + + case MULTISAMPLE_8X: + s_MSAASamples = 8; + break; + + case MULTISAMPLE_CSAA_8X: + s_MSAASamples = 4; s_MSAACoverageSamples = 8; + break; + + case MULTISAMPLE_CSAA_8XQ: + s_MSAASamples = 8; s_MSAACoverageSamples = 8; + break; + + case MULTISAMPLE_CSAA_16X: + s_MSAASamples = 4; s_MSAACoverageSamples = 16; + break; + + case MULTISAMPLE_CSAA_16XQ: + s_MSAASamples = 8; s_MSAACoverageSamples = 16; + break; + + default: + s_MSAASamples = 1; + break; + } + +#if defined HAVE_CG && HAVE_CG + g_cgcontext = cgCreateContext(); + cgGetError(); + cgSetErrorHandler(HandleCgError, NULL); +#endif + + // Look for required extensions. + const char *const ptoken = (const char*)glGetString(GL_EXTENSIONS); + if (!ptoken) + { + PanicAlert("Your OpenGL Driver seems to be not working.\n" + "Please make sure your drivers are up-to-date and\n" + "that your video hardware is OpenGL 2.x compatible."); + //return false; + return; + } + + INFO_LOG(VIDEO, "Supported OpenGL Extensions:"); + INFO_LOG(VIDEO, ptoken); // write to the log file + INFO_LOG(VIDEO, ""); + + OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", + glGetString(GL_VENDOR), + glGetString(GL_RENDERER), + glGetString(GL_VERSION)).c_str(), 5000); + + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs); + if (numvertexattribs < 11) + { + ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n" + "GPU: Does your video card support OpenGL 2.x?", + numvertexattribs); + bSuccess = false; + } + + // Init extension support. + if (glewInit() != GLEW_OK) + { + ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?"); + //return false; + + return; + } + + if (!GLEW_EXT_framebuffer_object) + { + ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets.\n" + "GPU: Does your video card support OpenGL 2.x?"); + bSuccess = false; + } + + if (!GLEW_EXT_secondary_color) + { + ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n" + "GPU: Does your video card support OpenGL 2.x?"); + bSuccess = false; + } + + s_bHaveFramebufferBlit = strstr(ptoken, "GL_EXT_framebuffer_blit") != NULL; + if (!s_bHaveFramebufferBlit) + { + // MSAA ain't gonna work. turn it off if enabled. + s_MSAASamples = 1; + } + + s_bHaveCoverageMSAA = strstr(ptoken, "GL_NV_framebuffer_multisample_coverage") != NULL; + if (!s_bHaveCoverageMSAA) + { + s_MSAACoverageSamples = 0; + } + + if (!bSuccess) + //return false; + return; + + // Handle VSync on/off +#if defined USE_WX && USE_WX + // TODO: FILL IN +#elif defined _WIN32 + if (WGLEW_EXT_swap_control) + wglSwapIntervalEXT(g_ActiveConfig.bVSync ? 1 : 0); + else + ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); +#elif defined(HAVE_X11) && HAVE_X11 + if (glXSwapIntervalSGI) + glXSwapIntervalSGI(g_ActiveConfig.bVSync ? 1 : 0); + else + ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); +#endif + + // check the max texture width and height + GLint max_texture_size; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size); + if (max_texture_size < 1024) + ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.", + max_texture_size); + + if (GL_REPORT_ERROR() != GL_NO_ERROR) + bSuccess = false; + + if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers) + glDrawBuffers = glDrawBuffersARB; + + if (!GLEW_ARB_texture_non_power_of_two) + WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported."); + + // Decide frambuffer size + FramebufferSize((int)OpenGL_GetBackbufferWidth(), (int)OpenGL_GetBackbufferHeight()); + + // Because of the fixed framebuffer size we need to disable the resolution + // options while running + g_Config.bRunning = true; + + if (GL_REPORT_ERROR() != GL_NO_ERROR) + bSuccess = false; + + // Initialize the FramebufferManager + g_framebuffer_manager = new FramebufferManager(s_backbuffer_width, + s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + if (GL_REPORT_ERROR() != GL_NO_ERROR) + bSuccess = false; + + s_pfont = new RasterFont(); + +#if defined HAVE_CG && HAVE_CG + // load the effect, find the best profiles (if any) + if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE) + { + ERROR_LOG(VIDEO, "arbvp1 not supported"); + return false; + } + + if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE) + { + ERROR_LOG(VIDEO, "arbfp1 not supported"); + return false; + } + + g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX); + g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); +#if CG_VERSION_NUM == 2100 + // A bug was introduced in Cg2.1's handling of very large profile option values + // so this will not work on ATI. ATI returns MAXINT = 2147483647 (0x7fffffff) + // which is correct in OpenGL but Cg fails to handle it properly. As a result + // -1 is used by Cg resulting (signedness incorrect) and compilation fails. + if (strstr((const char*)glGetString(GL_VENDOR), "ATI") == NULL) +#endif + { + cgGLSetOptimalOptions(g_cgvProf); + cgGLSetOptimalOptions(g_cgfProf); + } +#endif // HAVE_CG + + int nenvvertparams, nenvfragparams, naddrregisters[2]; + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, + GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, + (GLint *)&nenvvertparams); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, + GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, + (GLint *)&nenvfragparams); + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, + GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, + (GLint *)&naddrregisters[0]); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, + GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, + (GLint *)&naddrregisters[1]); + DEBUG_LOG(VIDEO, "Max program env parameters: vert=%d, frag=%d", + nenvvertparams, nenvfragparams); + DEBUG_LOG(VIDEO, "Max program address register parameters: vert=%d, frag=%d", + naddrregisters[0], naddrregisters[1]); + + if (nenvvertparams < 238) + ERROR_LOG(VIDEO, "Not enough vertex shader environment constants!!"); + +#if defined HAVE_CG && HAVE_CG + INFO_LOG(VIDEO, "Max buffer sizes: %d %d", + cgGetProgramBufferMaxSize(g_cgvProf), + cgGetProgramBufferMaxSize(g_cgfProf)); +#ifndef _DEBUG + cgGLSetDebugMode(GL_FALSE); +#endif +#endif + + glStencilFunc(GL_ALWAYS, 0, 0); + glBlendFunc(GL_ONE, GL_ONE); + + glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDepthFunc(GL_LEQUAL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment + + glDisable(GL_STENCIL_TEST); + glEnable(GL_SCISSOR_TEST); + + glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); + glBlendColorEXT(0, 0, 0, 0.5f); + glClearDepth(1.0f); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // legacy multitexturing: select texture channel only. + glActiveTexture(GL_TEXTURE0); + glClientActiveTexture(GL_TEXTURE0); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + UpdateActiveConfig(); + //return GL_REPORT_ERROR() == GL_NO_ERROR && bSuccess; + + return; +} + +Renderer::~Renderer() +{ + g_Config.bRunning = false; + UpdateActiveConfig(); + delete s_pfont; + s_pfont = 0; + +#if defined HAVE_CG && HAVE_CG + if (g_cgcontext) + { + cgDestroyContext(g_cgcontext); + g_cgcontext = 0; + } +#endif + + delete g_framebuffer_manager; + +//#ifdef _WIN32 +// if(s_bAVIDumping) +// AVIDump::Stop(); +//#else +// if(f_pFrameDump != NULL) +// fclose(f_pFrameDump); +//#endif + + OpenGL_Shutdown(); +} + +// For the OSD menu's live resolution change +bool Renderer::Allow2x() +{ + if (GetFrameBufferWidth() >= 1280 && GetFrameBufferHeight() >= 960) + return true; + else + return false; +} + +bool Renderer::AllowCustom() +{ + //if (GetCustomWidth() <= GetFrameBufferWidth() && GetCustomHeight() <= GetFrameBufferHeight()) + // return true; + //else + // return false; + + return false; +} + +void Renderer::ResetAPIState() +{ + // Gets us to a reasonably sane state where it's possible to do things like + // image copies with textured quads, etc. + VertexShaderCache::DisableShader(); + PixelShaderCache::DisableShader(); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +} + +void UpdateViewport(); + +void Renderer::RestoreAPIState() +{ + // Gets us back into a more game-like state. + + UpdateViewport(); + + if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE); + if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); + if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); + + glEnable(GL_SCISSOR_TEST); + SetScissorRect(); + SetColorMask(); + SetBlendMode(true); + + VertexShaderCache::SetCurrentShader(0); + PixelShaderCache::SetCurrentShader(0); +} + +void Renderer::SetColorMask() +{ + GLenum ColorMask = (bpmem.blendmode.colorupdate) ? GL_TRUE : GL_FALSE; + GLenum AlphaMask = (bpmem.blendmode.alphaupdate) ? GL_TRUE : GL_FALSE; + glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); +} + +void Renderer::SetBlendMode(bool forceUpdate) +{ + // blend mode bit mask + // 0 - blend enable + // 2 - reverse subtract enable (else add) + // 3-5 - srcRGB function + // 6-8 - dstRGB function + + u32 newval = bpmem.blendmode.subtract << 2; + + if (bpmem.blendmode.subtract) + newval |= 0x0049; // enable blending src 1 dst 1 + else if (bpmem.blendmode.blendenable) + { + newval |= 1; // enable blending + newval |= bpmem.blendmode.srcfactor << 3; + newval |= bpmem.blendmode.dstfactor << 6; + } + + u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; + + if (changes & 1) + // blend enable change + (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + + if (changes & 4) + // subtract enable change + glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD); + + if (changes & 0x1F8) + // blend RGB change + glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); + + s_blendMode = newval; +} + +u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +{ + if(!g_ActiveConfig.bEFBAccessEnable) + return 0; + + // Get the rectangular target region covered by the EFB pixel. + EFBRectangle efbPixelRc; + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + + TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); + + // TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel + switch (type) + { + + case PEEK_Z: + { + if (s_MSAASamples > 1) + { + // Resolve our rectangle. + FramebufferManager::GetEFBDepthTexture(efbPixelRc); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer()); + } + + // Sample from the center of the target region. + int srcX = (targetPixelRc.left + targetPixelRc.right) / 2; + int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2; + + u32 z = 0; + glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z); + GL_REPORT_ERRORD(); + + // Scale the 32-bit value returned by glReadPixels to a 24-bit + // value (GC uses a 24-bit Z-buffer). + // TODO: in RE0 this value is often off by one, which causes lighting to disappear + return z >> 8; + } + + case POKE_Z: + // TODO: Implement + break; + + case PEEK_COLOR: // GXPeekARGB + { + // Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit... + + // Tested in Killer 7, the first 8bits represent the alpha value which is used to + // determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70) + // Wind Waker is also using it for the pictograph to determine the color of each pixel + + if (s_MSAASamples > 1) + { + // Resolve our rectangle. + FramebufferManager::GetEFBColorTexture(efbPixelRc); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer()); + } + + // Sample from the center of the target region. + int srcX = (targetPixelRc.left + targetPixelRc.right) / 2; + int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2; + + // Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format. + u32 color = 0; + glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color); + GL_REPORT_ERRORD(); + + return color; + } + + case POKE_COLOR: + // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at + // the exact location. Note: EFB pokes are susceptible to Z-buffering + // and perhaps blending. + //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering"); + break; + + } + + return 0; +} + +// Function: This function handles the OpenGL glScissor() function +// ---------------------------- +// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() +// case 0x52 > SetScissorRect() +// ---------------------------- +// bpmem.scissorTL.x, y = 342x342 +// bpmem.scissorBR.x, y = 981x821 +// GetTargetHeight() = the fixed ini file setting +// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box +// therefore the width and height are (scissorBR + 1) - scissorTL +bool Renderer::SetScissorRect() +{ + EFBRectangle rc; + if (g_renderer->SetScissorRect(rc)) + { + glScissor( + (int)(rc.left * EFBxScale), // x = 0 for example + (int)((EFB_HEIGHT - rc.bottom) * EFByScale), // y = 0 for example + (int)((rc.right - rc.left) * EFBxScale), // width = 640 for example + (int)((rc.bottom - rc.top) * EFByScale) // height = 480 for example + ); + return true; + } + else + { + glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); + } + return false; +} + +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, + bool alphaEnable, bool zEnable, u32 color, u32 z) +{ + // Update the view port for clearing the picture + TargetRectangle targetRc = ConvertEFBRectangle(rc); + glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); + glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight()); + + // Always set the scissor in case it was set by the game and has not been reset + + VertexShaderManager::SetViewportChanged(); + + GLbitfield bits = 0; + if (colorEnable) + { + bits |= GL_COLOR_BUFFER_BIT; + glClearColor( + ((color >> 16) & 0xFF) / 255.0f, + ((color >> 8) & 0xFF) / 255.0f, + (color & 0xFF) / 255.0f, + ((color >> 24) & 0xFF) / 255.0f + ); + } + if (zEnable) + { + bits |= GL_DEPTH_BUFFER_BIT; + glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF)); + } + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glClear(bits); + SetScissorRect(); +} + +void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect) +{ + // Update GLViewPort + glViewport(dst_rect.left, dst_rect.bottom, dst_rect.GetWidth(), dst_rect.GetHeight()); + + GL_REPORT_ERRORD(); + + // Copy the framebuffer to screen. + + // Texture map s_xfbTexture onto the main buffer + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + // Use linear filtering. + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + +void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) +{ + // testing + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + if (xfbSource) + { + // Texture map xfbSource->texture onto the main buffer + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ((XFBSource*)xfbSource)->texture); + } + else + { + // Render to the real buffer now. + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, FramebufferManager::ResolveAndGetRenderTarget(rc)); + } + + // We must call ApplyShader here even if no post proc is selected - it takes + // care of disabling it in that case. It returns false in case of no post processing. + bool applyShader = PostProcessing::ApplyShader(); + if (applyShader) + { + glBegin(GL_QUADS); + glTexCoord2f(sourceRc.left, sourceRc.bottom); + glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0); + glVertex2f(drawRc.left, drawRc.bottom); + + glTexCoord2f(sourceRc.left, sourceRc.top); + glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1); + glVertex2f(drawRc.left, drawRc.top); + + glTexCoord2f(sourceRc.right, sourceRc.top); + glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1); + glVertex2f(drawRc.right, drawRc.top); + + glTexCoord2f(sourceRc.right, sourceRc.bottom); + glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0); + glVertex2f(drawRc.right, drawRc.bottom); + glEnd(); + PixelShaderCache::DisableShader(); + } + else + { + glBegin(GL_QUADS); + glTexCoord2f(sourceRc.left, sourceRc.bottom); + glVertex2f(drawRc.left, drawRc.bottom); + + glTexCoord2f(sourceRc.left, sourceRc.top); + glVertex2f(drawRc.left, drawRc.top); + + glTexCoord2f(sourceRc.right, sourceRc.top); + glVertex2f(drawRc.right, drawRc.top); + + glTexCoord2f(sourceRc.right, sourceRc.bottom); + glVertex2f(drawRc.right, drawRc.bottom); + glEnd(); + } + + GL_REPORT_ERRORD(); + + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureCache::DisableStage(0); + + // TODO: silly place for this + // Wireframe + if (g_ActiveConfig.bWireFrame) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +} + +void Renderer::EndFrame() +{ + // Copy the rendered frame to the real window + OpenGL_SwapBuffers(); + + GL_REPORT_ERRORD(); + + // Clear framebuffer + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + GL_REPORT_ERRORD(); +} + +void Renderer::Present() +{ + // Render to the framebuffer. + FramebufferManager::SetFramebuffer(0); + + GL_REPORT_ERRORD(); +} + +bool Renderer::CheckForResize() +{ + // TODO: temp + + OpenGL_Update(); // just updates the render window position and the backbuffer size + return true; +} + +void Renderer::GetBackBufferSize(int* w, int* h) +{ + *w = (int)OpenGL_GetBackbufferWidth(); + *h = (int)OpenGL_GetBackbufferHeight(); +} + +void Renderer::RecreateFramebufferManger() +{ + delete g_framebuffer_manager; + g_framebuffer_manager = new FramebufferManager(s_backbuffer_width, + s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); +} + +void Renderer::BeginFrame() +{ + // TODO: silly place for this + g_Config.iSaveTargetId = 0; + + bool last_copy_efb_to_Texture = g_ActiveConfig.bCopyEFBToTexture; + UpdateActiveConfig(); + if (last_copy_efb_to_Texture != g_ActiveConfig.bCopyEFBToTexture) + TextureCache::ClearRenderTargets(); +} + +// Called from VertexShaderManager +void Renderer::UpdateViewport() +{ + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz + float scissorXOff = float(bpmem.scissorOffset.x) * 2.0f; // 342 + float scissorYOff = float(bpmem.scissorOffset.y) * 2.0f; // 342 + + // Stretch picture with increased internal resolution + int GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - scissorXOff) * + EFBxScale); + int GLy = (int)ceil( + (float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + scissorYOff) * + EFByScale); + int GLWidth = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale); + int GLHeight = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale); + double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f; + double GLFar = xfregs.rawViewport[5] / 16777216.0f; + if(GLWidth < 0) + { + GLx += GLWidth; + GLWidth*=-1; + } + if(GLHeight < 0) + { + GLy += GLHeight; + GLHeight *= -1; + } + // Update the view port + glViewport(GLx, GLy, GLWidth, GLHeight); + glDepthRange(GLNear, GLFar); +} + +void Renderer::SetGenerationMode() +{ + // none, ccw, cw, ccw + if (bpmem.genMode.cullmode > 0) + { + glEnable(GL_CULL_FACE); + glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); + } + else + glDisable(GL_CULL_FACE); +} + +void Renderer::SetDepthMode() +{ + if (bpmem.zmode.testenable) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); + glDepthFunc(glCmpFuncs[bpmem.zmode.func]); + } + else + { + // if the test is disabled write is disabled too + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } +} + +void Renderer::SetLogicOpMode() +{ + if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3) + { + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]); + } + else + glDisable(GL_COLOR_LOGIC_OP); +} + +void Renderer::SetDitherMode() +{ + if (bpmem.blendmode.dither) + glEnable(GL_DITHER); + else + glDisable(GL_DITHER); +} + +void Renderer::SetLineWidth() +{ + float fratio = xfregs.rawViewport[0] != 0 ? + ((float)GetTargetWidth() / EFB_WIDTH) : 1.0f; + if (bpmem.lineptwidth.linesize > 0) + // scale by ratio of widths + glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); + if (bpmem.lineptwidth.pointsize > 0) + glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.h index 28d2a28f61..e5ccebb0c2 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.h @@ -1,61 +1,61 @@ - -#ifndef _OGL_RENDER_H_ -#define _OGL_RENDER_H_ - -#include "MathUtil.h" - -#include "VideoCommon.h" -#include "Renderer.h" -#include "pluginspecs_video.h" - -namespace OGL -{ - -extern int OSDChoice; - -class Renderer : public ::RendererBase -{ -public: - Renderer(); - ~Renderer(); - - // What's the real difference between these? Too similar names. - void ResetAPIState(); - void RestoreAPIState(); - - void SetColorMask(); - void SetBlendMode(bool forceUpdate); - bool SetScissorRect(); - void SetGenerationMode(); - void SetDepthMode(); - void SetLogicOpMode(); - void SetDitherMode(); - void SetLineWidth(); - - // Live resolution change - bool Allow2x(); - bool AllowCustom(); - - u32 AccessEFB(EFBAccessType type, int x, int y); - - void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); - void UpdateViewport(); - - // virtual funcs used by RendererBase::Swap - void PrepareXFBCopy(const TargetRectangle &dst_rect); - void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); - void EndFrame(); - void Present(); - bool CheckForResize(); - void GetBackBufferSize(int* w, int* h); - void RecreateFramebufferManger(); - void BeginFrame(); - -private: - -}; - -} - -#endif + +#ifndef _OGL_RENDER_H_ +#define _OGL_RENDER_H_ + +#include "MathUtil.h" + +#include "VideoCommon.h" +#include "Renderer.h" +#include "pluginspecs_video.h" + +namespace OGL +{ + +extern int OSDChoice; + +class Renderer : public ::RendererBase +{ +public: + Renderer(); + ~Renderer(); + + // What's the real difference between these? Too similar names. + void ResetAPIState(); + void RestoreAPIState(); + + void SetColorMask(); + void SetBlendMode(bool forceUpdate); + bool SetScissorRect(); + void SetGenerationMode(); + void SetDepthMode(); + void SetLogicOpMode(); + void SetDitherMode(); + void SetLineWidth(); + + // Live resolution change + bool Allow2x(); + bool AllowCustom(); + + u32 AccessEFB(EFBAccessType type, int x, int y); + + void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); + void UpdateViewport(); + + // virtual funcs used by RendererBase::Swap + void PrepareXFBCopy(const TargetRectangle &dst_rect); + void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc); + void EndFrame(); + void Present(); + bool CheckForResize(); + void GetBackBufferSize(int* w, int* h); + void RecreateFramebufferManger(); + void BeginFrame(); + +private: + +}; + +} + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.cpp index 3448607df1..0dd181db0a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.cpp @@ -1,339 +1,339 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include -#include - -#ifdef _WIN32 -#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set -#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset -#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64 -#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64 -#include -#undef _interlockedbittestandset -#undef _interlockedbittestandreset -#undef _interlockedbittestandset64 -#undef _interlockedbittestandreset64 -#endif - -// Common -#include "CommonPaths.h" -#include "StringUtil.h" -#include "MemoryUtil.h" -#include "FileUtil.h" - -// VideoCommon -#include "VideoConfig.h" -#include "Hash.h" -#include "Statistics.h" -#include "Profiler.h" -#include "ImageWrite.h" -#include "BPStructs.h" -#include "TextureDecoder.h" -#include "PixelShaderManager.h" -#include "HiresTextures.h" -#include "VertexShaderManager.h" - -// OGL -#include "OGL_TextureCache.h" -#include "OGL_PixelShaderCache.h" -#include "OGL_TextureConverter.h" -#include "OGL_FramebufferManager.h" - -#include "../Main.h" - -namespace OGL -{ - -static u32 s_TempFramebuffer = 0; - -static const GLint c_MinLinearFilter[8] = { - GL_NEAREST, - GL_NEAREST_MIPMAP_NEAREST, - GL_NEAREST_MIPMAP_LINEAR, - GL_NEAREST, - GL_LINEAR, - GL_LINEAR_MIPMAP_NEAREST, - GL_LINEAR_MIPMAP_LINEAR, - GL_LINEAR, -}; - -static const GLint c_WrapSettings[4] = { - GL_CLAMP_TO_EDGE, - GL_REPEAT, - GL_MIRRORED_REPEAT, - GL_REPEAT, -}; - -TextureCache::TCacheEntry::~TCacheEntry() -{ - if (texture) - { - glDeleteTextures(1, &texture); - texture = 0; - } -} - -TextureCache::TCacheEntry::TCacheEntry() -{ - glGenTextures(1, &texture); - GL_REPORT_ERRORD(); -} - -void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level) -{ - if (bHaveMipMaps) - { - if (pcfmt != PC_TEX_FMT_DXT1) - { - if (expanded_width != (int)width) - glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); - - glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp); - - if (expanded_width != (int)width) - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - else - { - // TODO: - //glCompressedTexImage2D(target, level, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, width, height, 0, expanded_width*expanded_height/2, temp); - } - } - else - { - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); - } -} - -void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) -{ - glBindTexture(GL_TEXTURE_2D, texture); - - // Make sure to resolve anything we need to read from. - const GLuint read_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source_rect) : FramebufferManager::ResolveAndGetRenderTarget(source_rect); - - GL_REPORT_ERRORD(); - - if (s_TempFramebuffer == 0) - glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer); - - FramebufferManager::SetFramebuffer(s_TempFramebuffer); - // Bind texture to temporary framebuffer - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0); - GL_REPORT_FBO_ERROR(); - GL_REPORT_ERRORD(); - - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture); - - glViewport(0, 0, Scaledw, Scaledh); - - PixelShaderCache::SetCurrentShader(bFromZBuffer ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram()); - const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat - PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation - - GL_REPORT_ERRORD(); - - TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect); - - glBegin(GL_QUADS); - glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1); - glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1); - glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1); - glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1); - glEnd(); - - GL_REPORT_ERRORD(); - - // Unbind texture from temporary framebuffer - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); - - // TODO: these good here? - FramebufferManager::SetFramebuffer(0); - VertexShaderManager::SetViewportChanged(); - DisableStage(0); - - GL_REPORT_ERRORD(); - - // TODO: do this? - //glBindTexture(GL_TEXTURE_2D, 0); -} - -void TextureCache::TCacheEntry::Bind(unsigned int stage) -{ - glBindTexture(GL_TEXTURE_2D, texture); -} - -TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, - unsigned int height, unsigned int expanded_width, - unsigned int tex_levels, PC_TexFormat pcfmt) -{ - TCacheEntry &entry = *new TCacheEntry; - - int gl_format = 0; - int gl_iformat = 0; - int gl_type = 0; - - if (pcfmt != PC_TEX_FMT_DXT1) - { - switch (pcfmt) - { - default: - case PC_TEX_FMT_NONE: - PanicAlert("Invalid PC texture format %i", pcfmt); - case PC_TEX_FMT_BGRA32: - gl_format = GL_BGRA; - gl_iformat = 4; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_RGBA32: - gl_format = GL_RGBA; - gl_iformat = 4; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_I4_AS_I8: - gl_format = GL_LUMINANCE; - gl_iformat = GL_INTENSITY4; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_IA4_AS_IA8: - gl_format = GL_LUMINANCE_ALPHA; - gl_iformat = GL_LUMINANCE4_ALPHA4; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_I8: - gl_format = GL_LUMINANCE; - gl_iformat = GL_INTENSITY8; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_IA8: - gl_format = GL_LUMINANCE_ALPHA; - gl_iformat = GL_LUMINANCE8_ALPHA8; - gl_type = GL_UNSIGNED_BYTE; - break; - - case PC_TEX_FMT_RGB565: - gl_format = GL_RGB; - gl_iformat = GL_RGB; - gl_type = GL_UNSIGNED_SHORT_5_6_5; - break; - } - } - - entry.gl_format = gl_format; - entry.gl_iformat = gl_iformat; - entry.gl_type = gl_type; - - // ok? - //Load(width, height, expanded_width, level); - - return &entry; -} - -TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) -{ - TCacheEntry &entry = *new TCacheEntry; - - entry.isDynamic = false; - - glBindTexture(GL_TEXTURE_2D, entry.texture); - GL_REPORT_ERRORD(); - - const GLenum gl_format = GL_RGBA, - gl_iformat = 4, - gl_type = GL_UNSIGNED_BYTE; - glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_w, 0, gl_format, gl_type, NULL); - - GL_REPORT_ERRORD(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (GL_REPORT_ERROR() != GL_NO_ERROR) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - GL_REPORT_ERRORD(); - } - - return &entry; -} - -void TextureCache::TCacheEntry::SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1) -{ - mode = newmode; - //mode1 = newmode1; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - (newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST); - - if (bHaveMipMaps) - { - if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4) - mode.min_filter += 4; // take equivalent forced linear - - int filt = newmode.min_filter; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod >> 4); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod >> 4); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias/32.0f)); - - } - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - (g_ActiveConfig.bForceFiltering || newmode.min_filter >= 4) ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]); - - if (g_Config.iMaxAnisotropy >= 1) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy)); - -} - -TextureCache::~TextureCache() -{ - if (s_TempFramebuffer) - { - glDeleteFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer); - s_TempFramebuffer = 0; - } -} - -void TextureCache::DisableStage(int stage) -{ - glActiveTexture(GL_TEXTURE0 + stage); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_RECTANGLE_ARB); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include +#include + +#ifdef _WIN32 +#define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set +#define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset +#define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64 +#define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64 +#include +#undef _interlockedbittestandset +#undef _interlockedbittestandreset +#undef _interlockedbittestandset64 +#undef _interlockedbittestandreset64 +#endif + +// Common +#include "CommonPaths.h" +#include "StringUtil.h" +#include "MemoryUtil.h" +#include "FileUtil.h" + +// VideoCommon +#include "VideoConfig.h" +#include "Hash.h" +#include "Statistics.h" +#include "Profiler.h" +#include "ImageWrite.h" +#include "BPStructs.h" +#include "TextureDecoder.h" +#include "PixelShaderManager.h" +#include "HiresTextures.h" +#include "VertexShaderManager.h" + +// OGL +#include "OGL_TextureCache.h" +#include "OGL_PixelShaderCache.h" +#include "OGL_TextureConverter.h" +#include "OGL_FramebufferManager.h" + +#include "../Main.h" + +namespace OGL +{ + +static u32 s_TempFramebuffer = 0; + +static const GLint c_MinLinearFilter[8] = { + GL_NEAREST, + GL_NEAREST_MIPMAP_NEAREST, + GL_NEAREST_MIPMAP_LINEAR, + GL_NEAREST, + GL_LINEAR, + GL_LINEAR_MIPMAP_NEAREST, + GL_LINEAR_MIPMAP_LINEAR, + GL_LINEAR, +}; + +static const GLint c_WrapSettings[4] = { + GL_CLAMP_TO_EDGE, + GL_REPEAT, + GL_MIRRORED_REPEAT, + GL_REPEAT, +}; + +TextureCache::TCacheEntry::~TCacheEntry() +{ + if (texture) + { + glDeleteTextures(1, &texture); + texture = 0; + } +} + +TextureCache::TCacheEntry::TCacheEntry() +{ + glGenTextures(1, &texture); + GL_REPORT_ERRORD(); +} + +void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level) +{ + if (bHaveMipMaps) + { + if (pcfmt != PC_TEX_FMT_DXT1) + { + if (expanded_width != (int)width) + glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width); + + glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp); + + if (expanded_width != (int)width) + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + else + { + // TODO: + //glCompressedTexImage2D(target, level, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, width, height, 0, expanded_width*expanded_height/2, temp); + } + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, width, height, 0, gl_format, gl_type, TextureCache::temp); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); + } +} + +void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) +{ + glBindTexture(GL_TEXTURE_2D, texture); + + // Make sure to resolve anything we need to read from. + const GLuint read_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source_rect) : FramebufferManager::ResolveAndGetRenderTarget(source_rect); + + GL_REPORT_ERRORD(); + + if (s_TempFramebuffer == 0) + glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer); + + FramebufferManager::SetFramebuffer(s_TempFramebuffer); + // Bind texture to temporary framebuffer + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0); + GL_REPORT_FBO_ERROR(); + GL_REPORT_ERRORD(); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, read_texture); + + glViewport(0, 0, Scaledw, Scaledh); + + PixelShaderCache::SetCurrentShader(bFromZBuffer ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram()); + const float* const fConstAdd = colmat + 16; // fConstAdd is the last 4 floats of colmat + PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation + + GL_REPORT_ERRORD(); + + TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(source_rect); + + glBegin(GL_QUADS); + glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.bottom); glVertex2f(-1, 1); + glTexCoord2f((GLfloat)targetSource.left, (GLfloat)targetSource.top ); glVertex2f(-1, -1); + glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.top ); glVertex2f( 1, -1); + glTexCoord2f((GLfloat)targetSource.right, (GLfloat)targetSource.bottom); glVertex2f( 1, 1); + glEnd(); + + GL_REPORT_ERRORD(); + + // Unbind texture from temporary framebuffer + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); + + // TODO: these good here? + FramebufferManager::SetFramebuffer(0); + VertexShaderManager::SetViewportChanged(); + DisableStage(0); + + GL_REPORT_ERRORD(); + + // TODO: do this? + //glBindTexture(GL_TEXTURE_2D, 0); +} + +void TextureCache::TCacheEntry::Bind(unsigned int stage) +{ + glBindTexture(GL_TEXTURE_2D, texture); +} + +TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, + unsigned int height, unsigned int expanded_width, + unsigned int tex_levels, PC_TexFormat pcfmt) +{ + TCacheEntry &entry = *new TCacheEntry; + + int gl_format = 0; + int gl_iformat = 0; + int gl_type = 0; + + if (pcfmt != PC_TEX_FMT_DXT1) + { + switch (pcfmt) + { + default: + case PC_TEX_FMT_NONE: + PanicAlert("Invalid PC texture format %i", pcfmt); + case PC_TEX_FMT_BGRA32: + gl_format = GL_BGRA; + gl_iformat = 4; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_RGBA32: + gl_format = GL_RGBA; + gl_iformat = 4; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_I4_AS_I8: + gl_format = GL_LUMINANCE; + gl_iformat = GL_INTENSITY4; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_IA4_AS_IA8: + gl_format = GL_LUMINANCE_ALPHA; + gl_iformat = GL_LUMINANCE4_ALPHA4; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_I8: + gl_format = GL_LUMINANCE; + gl_iformat = GL_INTENSITY8; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_IA8: + gl_format = GL_LUMINANCE_ALPHA; + gl_iformat = GL_LUMINANCE8_ALPHA8; + gl_type = GL_UNSIGNED_BYTE; + break; + + case PC_TEX_FMT_RGB565: + gl_format = GL_RGB; + gl_iformat = GL_RGB; + gl_type = GL_UNSIGNED_SHORT_5_6_5; + break; + } + } + + entry.gl_format = gl_format; + entry.gl_iformat = gl_iformat; + entry.gl_type = gl_type; + + // ok? + //Load(width, height, expanded_width, level); + + return &entry; +} + +TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) +{ + TCacheEntry &entry = *new TCacheEntry; + + entry.isDynamic = false; + + glBindTexture(GL_TEXTURE_2D, entry.texture); + GL_REPORT_ERRORD(); + + const GLenum gl_format = GL_RGBA, + gl_iformat = 4, + gl_type = GL_UNSIGNED_BYTE; + glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_w, 0, gl_format, gl_type, NULL); + + GL_REPORT_ERRORD(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (GL_REPORT_ERROR() != GL_NO_ERROR) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + GL_REPORT_ERRORD(); + } + + return &entry; +} + +void TextureCache::TCacheEntry::SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1) +{ + mode = newmode; + //mode1 = newmode1; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + (newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST); + + if (bHaveMipMaps) + { + if (g_ActiveConfig.bForceFiltering && newmode.min_filter < 4) + mode.min_filter += 4; // take equivalent forced linear + + int filt = newmode.min_filter; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c_MinLinearFilter[filt & 7]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, newmode1.min_lod >> 4); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, newmode1.max_lod >> 4); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, (newmode.lod_bias/32.0f)); + + } + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + (g_ActiveConfig.bForceFiltering || newmode.min_filter >= 4) ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c_WrapSettings[newmode.wrap_s]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, c_WrapSettings[newmode.wrap_t]); + + if (g_Config.iMaxAnisotropy >= 1) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy)); + +} + +TextureCache::~TextureCache() +{ + if (s_TempFramebuffer) + { + glDeleteFramebuffersEXT(1, (GLuint *)&s_TempFramebuffer); + s_TempFramebuffer = 0; + } +} + +void TextureCache::DisableStage(int stage) +{ + glActiveTexture(GL_TEXTURE0 + stage); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_RECTANGLE_ARB); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.h index 3e648e4031..cfb224d7a8 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureCache.h @@ -1,80 +1,80 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_TEXTURECACHE_H_ -#define _OGL_TEXTURECACHE_H_ - -#include "VideoCommon.h" -#include "BPMemory.h" - -#include "OGL_GLUtil.h" - -#include "../TextureCache.h" - -namespace OGL -{ - -class TextureCache : public ::TextureCacheBase -{ -public: - struct TCacheEntry : TCacheEntryBase - { - GLuint texture; - - bool isDynamic; - bool bHaveMipMaps; - - PC_TexFormat pcfmt; - - int gl_format; - int gl_iformat; - int gl_type; - - TexMode0 mode; // current filter and clamp modes that texture is set to - TexMode1 mode1; // current filter and clamp modes that texture is set to - - void SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1); - - TCacheEntry(); - ~TCacheEntry(); - - void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int level); - - void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); - - void Bind(unsigned int stage); - }; - - ~TextureCache(); - - TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); - - TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); - - void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source); - - static void DisableStage(int stage); // sets active texture -}; - -//bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); - -} - -#endif // _TEXTUREMNGR_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_TEXTURECACHE_H_ +#define _OGL_TEXTURECACHE_H_ + +#include "VideoCommon.h" +#include "BPMemory.h" + +#include "OGL_GLUtil.h" + +#include "../TextureCache.h" + +namespace OGL +{ + +class TextureCache : public ::TextureCacheBase +{ +public: + struct TCacheEntry : TCacheEntryBase + { + GLuint texture; + + bool isDynamic; + bool bHaveMipMaps; + + PC_TexFormat pcfmt; + + int gl_format; + int gl_iformat; + int gl_type; + + TexMode0 mode; // current filter and clamp modes that texture is set to + TexMode1 mode1; // current filter and clamp modes that texture is set to + + void SetTextureParameters(TexMode0 &newmode, TexMode1 &newmode1); + + TCacheEntry(); + ~TCacheEntry(); + + void Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level); + + void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect); + + void Bind(unsigned int stage); + }; + + ~TextureCache(); + + TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt); + + TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h); + + void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source); + + static void DisableStage(int stage); // sets active texture +}; + +//bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); + +} + +#endif // _TEXTUREMNGR_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.cpp index e95379aca0..8fb4edc299 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.cpp @@ -1,486 +1,486 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Fast image conversion using OpenGL shaders. -// This kind of stuff would be a LOT nicer with OpenCL. - -#include - -// Common -#include "FileUtil.h" - -// VideoCommon -#include "TextureConversionShader.h" -#include "VertexShaderManager.h" -#include "VideoConfig.h" -#include "ImageWrite.h" - -// OGL -#include "OGL_Render.h" -#include "OGL_TextureConverter.h" -#include "OGL_TextureCache.h" -#include "OGL_PixelShaderCache.h" -#include "OGL_FramebufferManager.h" - -#include "../Main.h" - -namespace OGL -{ - -namespace TextureConverter -{ - -static GLuint s_texConvFrameBuffer = 0; -static GLuint s_srcTexture = 0; // for decoding from RAM -static GLuint s_srcTextureWidth = 0; -static GLuint s_srcTextureHeight = 0; -static GLuint s_dstRenderBuffer = 0; // for encoding to RAM - -const int renderBufferWidth = 1024; -const int renderBufferHeight = 1024; - -static FRAGMENTSHADER s_rgbToYuyvProgram; -static FRAGMENTSHADER s_yuyvToRgbProgram; - -// Not all slots are taken - but who cares. -const u32 NUM_ENCODING_PROGRAMS = 64; -static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS]; - -void CreateRgbToYuyvProgram() -{ - // Output is BGRA because that is slightly faster than RGBA. - const char *FProgram = - "uniform samplerRECT samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float2 uv1 = float2(uv0.x + 1.0f, uv0.y);\n" - " float3 c0 = texRECT(samp0, uv0).rgb;\n" - " float3 c1 = texRECT(samp0, uv1).rgb;\n" - " float3 y_const = float3(0.257f,0.504f,0.098f);\n" - " float3 u_const = float3(-0.148f,-0.291f,0.439f);\n" - " float3 v_const = float3(0.439f,-0.368f,-0.071f);\n" - " float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n" - " float3 c01 = (c0 + c1) * 0.5f;\n" - " ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" - "}\n"; - - if (!PixelShaderCache::CompilePixelShader(s_rgbToYuyvProgram, FProgram)) { - ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program"); - } -} - -void CreateYuyvToRgbProgram() -{ - const char *FProgram = - "uniform samplerRECT samp0 : register(s0);\n" - "void main(\n" - " out float4 ocol0 : COLOR0,\n" - " in float2 uv0 : TEXCOORD0)\n" - "{\n" - " float4 c0 = texRECT(samp0, uv0).rgba;\n" - - " float f = step(0.5, frac(uv0.x));\n" - " float y = lerp(c0.b, c0.r, f);\n" - " float yComp = 1.164f * (y - 0.0625f);\n" - " float uComp = c0.g - 0.5f;\n" - " float vComp = c0.a - 0.5f;\n" - - " ocol0 = float4(yComp + (1.596f * vComp),\n" - " yComp - (0.813f * vComp) - (0.391f * uComp),\n" - " yComp + (2.018f * uComp),\n" - " 1.0f);\n" - "}\n"; - - if (!PixelShaderCache::CompilePixelShader(s_yuyvToRgbProgram, FProgram)) { - ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program"); - } -} - -FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format) -{ - if (format > NUM_ENCODING_PROGRAMS) - { - PanicAlert("Unknown texture copy format: 0x%x\n", format); - return s_encodingPrograms[0]; - } - - if (s_encodingPrograms[format].glprogid == 0) - { - const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_OPENGL); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - - SaveData(szTemp, shader); - } -#endif - - if (!PixelShaderCache::CompilePixelShader(s_encodingPrograms[format], shader)) { - ERROR_LOG(VIDEO, "Failed to create encoding fragment program"); - } - } - - return s_encodingPrograms[format]; -} - -void Init() -{ - glGenFramebuffersEXT(1, &s_texConvFrameBuffer); - - glGenRenderbuffersEXT(1, &s_dstRenderBuffer); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight); - - glGenTextures(1, &s_srcTexture); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - CreateRgbToYuyvProgram(); - CreateYuyvToRgbProgram(); -} - -void Shutdown() -{ - glDeleteTextures(1, &s_srcTexture); - glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer); - glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer); - - s_rgbToYuyvProgram.Destroy(); - s_yuyvToRgbProgram.Destroy(); - - for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) - s_encodingPrograms[i].Destroy(); - - s_srcTexture = 0; - s_dstRenderBuffer = 0; - s_texConvFrameBuffer = 0; -} - -void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter) -{ - - - // switch to texture converter frame buffer - // attach render buffer as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer); - - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_dstRenderBuffer); - GL_REPORT_ERRORD(); - - for (int i = 1; i < 8; ++i) - TextureCache::DisableStage(i); - - // set source texture - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); - - if (linearFilter) - { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - GL_REPORT_ERRORD(); - - glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight); - - PixelShaderCache::SetCurrentShader(shader.glprogid); - - // Draw... - glBegin(GL_QUADS); - glTexCoord2f((float)sourceRc.left, (float)sourceRc.top); glVertex2f(-1,-1); - glTexCoord2f((float)sourceRc.left, (float)sourceRc.bottom); glVertex2f(-1,1); - glTexCoord2f((float)sourceRc.right, (float)sourceRc.bottom); glVertex2f(1,1); - glTexCoord2f((float)sourceRc.right, (float)sourceRc.top); glVertex2f(1,-1); - glEnd(); - GL_REPORT_ERRORD(); - - // .. and then readback the results. - // TODO: make this less slow. - - int writeStride = bpmem.copyMipMapStrideChannels * 32; - - if (writeStride != readStride && toTexture) - { - // writing to a texture of a different size - - int readHeight = readStride / dstWidth; - readHeight /= 4; // 4 bytes per pixel - - int readStart = 0; - int readLoops = dstHeight / readHeight; - for (int i = 0; i < readLoops; i++) - { - glReadPixels(0, readStart, (GLsizei)dstWidth, (GLsizei)readHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); - - readStart += readHeight; - destAddr += writeStride; - } - } - else - glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); - - GL_REPORT_ERRORD(); - -} - -void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) -{ - u32 format = copyfmt; - - if (bFromZBuffer) - { - format |= _GX_TF_ZTF; - if (copyfmt == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) - format |= _GX_TF_CTF; - - FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format); - if (texconv_shader.glprogid == 0) - return; - - u8 *dest_ptr = Memory_GetPtr(address); - - GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source); - - int width = (source.right - source.left) >> bScaleByHalf; - int height = (source.bottom - source.top) >> bScaleByHalf; - - int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); - - // Invalidate any existing texture covering this memory range. - // TODO - don't delete the texture if it already exists, just replace the contents. - TextureCache::InvalidateRange(address, size_in_bytes); - - u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; - u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; - u16 samples = TextureConversionShader::GetEncodedSampleCount(format); - - // only copy on cache line boundaries - // extra pixels are copied but not displayed in the resulting texture - s32 expandedWidth = (width + blkW) & (~blkW); - s32 expandedHeight = (height + blkH) & (~blkH); - - float MValueX = Renderer::GetTargetScaleX(); - float MValueY = Renderer::GetTargetScaleY(); - - float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ; - - float sampleStride = bScaleByHalf?2.0f:1.0f; - - TextureConversionShader::SetShaderParameters((float)expandedWidth, - expandedHeight * MValueY, - source.left * MValueX, - top, - sampleStride * MValueX, - sampleStride * MValueY); - - TargetRectangle scaledSource; - scaledSource.top = 0; - scaledSource.bottom = expandedHeight; - scaledSource.left = 0; - scaledSource.right = expandedWidth / samples; - - - int cacheBytes = 32; - if ((format & 0x0f) == 6) - cacheBytes = 64; - - int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); - g_renderer->ResetAPIState(); - EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0); - FramebufferManager::SetFramebuffer(0); - VertexShaderManager::SetViewportChanged(); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureCache::DisableStage(0); - g_renderer->RestoreAPIState(); - GL_REPORT_ERRORD(); -} - - -u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY,bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) -{ - u32 format = copyfmt; - - if (bFromZBuffer) - { - format |= _GX_TF_ZTF; - if (copyfmt == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) - format |= _GX_TF_CTF; - - FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format); - if (texconv_shader.glprogid == 0) - return 0; - - u8 *dest_ptr = Memory_GetPtr(address); - - int width = (source.right - source.left) >> bScaleByHalf; - int height = (source.bottom - source.top) >> bScaleByHalf; - - int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); - - u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; - u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; - u16 samples = TextureConversionShader::GetEncodedSampleCount(format); - - // only copy on cache line boundaries - // extra pixels are copied but not displayed in the resulting texture - s32 expandedWidth = (width + blkW) & (~blkW); - s32 expandedHeight = (height + blkH) & (~blkH); - - float sampleStride = bScaleByHalf?2.0f:1.0f; - float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ; - TextureConversionShader::SetShaderParameters((float)expandedWidth, - expandedHeight * MValueY, - source.left * MValueX, - top, - sampleStride * MValueX, - sampleStride * MValueY); - - TargetRectangle scaledSource; - scaledSource.top = 0; - scaledSource.bottom = expandedHeight; - scaledSource.left = 0; - scaledSource.right = expandedWidth / samples; - - - int cacheBytes = 32; - if ((format & 0x0f) == 6) - cacheBytes = 64; - - int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); - - EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0 && !bFromZBuffer); - g_texture_cache->MakeRangeDynamic(address,size_in_bytes); - return GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples); -} - -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight) -{ - g_renderer->ResetAPIState(); - EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); - FramebufferManager::SetFramebuffer(0); - VertexShaderManager::SetViewportChanged(); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - TextureCache::DisableStage(0); - g_renderer->RestoreAPIState(); - GL_REPORT_ERRORD(); -} - - -// Should be scale free. -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) -{ - u8* srcAddr = Memory_GetPtr(xfbAddr); - if (!srcAddr) - { - WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); - return; - } - - g_renderer->ResetAPIState(); - - int srcFmtWidth = srcWidth / 2; - - // swich to texture converter frame buffer - // attach destTexture as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0); - - GL_REPORT_FBO_ERROR(); - - for (int i = 1; i < 8; ++i) - TextureCache::DisableStage(i); - - // activate source texture - // set srcAddr as data for source texture - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); - - // TODO: make this less slow. (How?) - if((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight) - { - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,0,0,s_srcTextureWidth, s_srcTextureHeight, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); - } - else - { - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); - s_srcTextureWidth = (GLsizei)srcFmtWidth; - s_srcTextureHeight = (GLsizei)srcHeight; - } - - glViewport(0, 0, srcWidth, srcHeight); - - PixelShaderCache::SetCurrentShader(s_yuyvToRgbProgram.glprogid); - - GL_REPORT_ERRORD(); - - glBegin(GL_QUADS); - glTexCoord2f((float)srcFmtWidth, (float)srcHeight); - glVertex2f(1, -1); - glTexCoord2f((float)srcFmtWidth, 0); - glVertex2f(1, 1); - glTexCoord2f(0, 0); - glVertex2f(-1, 1); - glTexCoord2f(0, (float)srcHeight); - glVertex2f(-1, -1); - glEnd(); - - // reset state - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - TextureCache::DisableStage(0); - - VertexShaderManager::SetViewportChanged(); - - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); - GL_REPORT_ERRORD(); -} - -} // namespace - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Fast image conversion using OpenGL shaders. +// This kind of stuff would be a LOT nicer with OpenCL. + +#include + +// Common +#include "FileUtil.h" + +// VideoCommon +#include "TextureConversionShader.h" +#include "VertexShaderManager.h" +#include "VideoConfig.h" +#include "ImageWrite.h" + +// OGL +#include "OGL_Render.h" +#include "OGL_TextureConverter.h" +#include "OGL_TextureCache.h" +#include "OGL_PixelShaderCache.h" +#include "OGL_FramebufferManager.h" + +#include "../Main.h" + +namespace OGL +{ + +namespace TextureConverter +{ + +static GLuint s_texConvFrameBuffer = 0; +static GLuint s_srcTexture = 0; // for decoding from RAM +static GLuint s_srcTextureWidth = 0; +static GLuint s_srcTextureHeight = 0; +static GLuint s_dstRenderBuffer = 0; // for encoding to RAM + +const int renderBufferWidth = 1024; +const int renderBufferHeight = 1024; + +static FRAGMENTSHADER s_rgbToYuyvProgram; +static FRAGMENTSHADER s_yuyvToRgbProgram; + +// Not all slots are taken - but who cares. +const u32 NUM_ENCODING_PROGRAMS = 64; +static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS]; + +void CreateRgbToYuyvProgram() +{ + // Output is BGRA because that is slightly faster than RGBA. + const char *FProgram = + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float2 uv1 = float2(uv0.x + 1.0f, uv0.y);\n" + " float3 c0 = texRECT(samp0, uv0).rgb;\n" + " float3 c1 = texRECT(samp0, uv1).rgb;\n" + " float3 y_const = float3(0.257f,0.504f,0.098f);\n" + " float3 u_const = float3(-0.148f,-0.291f,0.439f);\n" + " float3 v_const = float3(0.439f,-0.368f,-0.071f);\n" + " float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n" + " float3 c01 = (c0 + c1) * 0.5f;\n" + " ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" + "}\n"; + + if (!PixelShaderCache::CompilePixelShader(s_rgbToYuyvProgram, FProgram)) { + ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program"); + } +} + +void CreateYuyvToRgbProgram() +{ + const char *FProgram = + "uniform samplerRECT samp0 : register(s0);\n" + "void main(\n" + " out float4 ocol0 : COLOR0,\n" + " in float2 uv0 : TEXCOORD0)\n" + "{\n" + " float4 c0 = texRECT(samp0, uv0).rgba;\n" + + " float f = step(0.5, frac(uv0.x));\n" + " float y = lerp(c0.b, c0.r, f);\n" + " float yComp = 1.164f * (y - 0.0625f);\n" + " float uComp = c0.g - 0.5f;\n" + " float vComp = c0.a - 0.5f;\n" + + " ocol0 = float4(yComp + (1.596f * vComp),\n" + " yComp - (0.813f * vComp) - (0.391f * uComp),\n" + " yComp + (2.018f * uComp),\n" + " 1.0f);\n" + "}\n"; + + if (!PixelShaderCache::CompilePixelShader(s_yuyvToRgbProgram, FProgram)) { + ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program"); + } +} + +FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format) +{ + if (format > NUM_ENCODING_PROGRAMS) + { + PanicAlert("Unknown texture copy format: 0x%x\n", format); + return s_encodingPrograms[0]; + } + + if (s_encodingPrograms[format].glprogid == 0) + { + const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_OPENGL); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + + SaveData(szTemp, shader); + } +#endif + + if (!PixelShaderCache::CompilePixelShader(s_encodingPrograms[format], shader)) { + ERROR_LOG(VIDEO, "Failed to create encoding fragment program"); + } + } + + return s_encodingPrograms[format]; +} + +void Init() +{ + glGenFramebuffersEXT(1, &s_texConvFrameBuffer); + + glGenRenderbuffersEXT(1, &s_dstRenderBuffer); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight); + + glGenTextures(1, &s_srcTexture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + CreateRgbToYuyvProgram(); + CreateYuyvToRgbProgram(); +} + +void Shutdown() +{ + glDeleteTextures(1, &s_srcTexture); + glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer); + glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer); + + s_rgbToYuyvProgram.Destroy(); + s_yuyvToRgbProgram.Destroy(); + + for (unsigned int i = 0; i < NUM_ENCODING_PROGRAMS; i++) + s_encodingPrograms[i].Destroy(); + + s_srcTexture = 0; + s_dstRenderBuffer = 0; + s_texConvFrameBuffer = 0; +} + +void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight, int readStride, bool toTexture, bool linearFilter) +{ + + + // switch to texture converter frame buffer + // attach render buffer as color destination + FramebufferManager::SetFramebuffer(s_texConvFrameBuffer); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_dstRenderBuffer); + GL_REPORT_ERRORD(); + + for (int i = 1; i < 8; ++i) + TextureCache::DisableStage(i); + + // set source texture + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexture); + + if (linearFilter) + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + GL_REPORT_ERRORD(); + + glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight); + + PixelShaderCache::SetCurrentShader(shader.glprogid); + + // Draw... + glBegin(GL_QUADS); + glTexCoord2f((float)sourceRc.left, (float)sourceRc.top); glVertex2f(-1,-1); + glTexCoord2f((float)sourceRc.left, (float)sourceRc.bottom); glVertex2f(-1,1); + glTexCoord2f((float)sourceRc.right, (float)sourceRc.bottom); glVertex2f(1,1); + glTexCoord2f((float)sourceRc.right, (float)sourceRc.top); glVertex2f(1,-1); + glEnd(); + GL_REPORT_ERRORD(); + + // .. and then readback the results. + // TODO: make this less slow. + + int writeStride = bpmem.copyMipMapStrideChannels * 32; + + if (writeStride != readStride && toTexture) + { + // writing to a texture of a different size + + int readHeight = readStride / dstWidth; + readHeight /= 4; // 4 bytes per pixel + + int readStart = 0; + int readLoops = dstHeight / readHeight; + for (int i = 0; i < readLoops; i++) + { + glReadPixels(0, readStart, (GLsizei)dstWidth, (GLsizei)readHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); + + readStart += readHeight; + destAddr += writeStride; + } + } + else + glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); + + GL_REPORT_ERRORD(); + +} + +void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) +{ + u32 format = copyfmt; + + if (bFromZBuffer) + { + format |= _GX_TF_ZTF; + if (copyfmt == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) + format |= _GX_TF_CTF; + + FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format); + if (texconv_shader.glprogid == 0) + return; + + u8 *dest_ptr = Memory_GetPtr(address); + + GLuint source_texture = bFromZBuffer ? FramebufferManager::ResolveAndGetDepthTarget(source) : FramebufferManager::ResolveAndGetRenderTarget(source); + + int width = (source.right - source.left) >> bScaleByHalf; + int height = (source.bottom - source.top) >> bScaleByHalf; + + int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); + + // Invalidate any existing texture covering this memory range. + // TODO - don't delete the texture if it already exists, just replace the contents. + TextureCache::InvalidateRange(address, size_in_bytes); + + u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; + u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; + u16 samples = TextureConversionShader::GetEncodedSampleCount(format); + + // only copy on cache line boundaries + // extra pixels are copied but not displayed in the resulting texture + s32 expandedWidth = (width + blkW) & (~blkW); + s32 expandedHeight = (height + blkH) & (~blkH); + + float MValueX = Renderer::GetTargetScaleX(); + float MValueY = Renderer::GetTargetScaleY(); + + float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ; + + float sampleStride = bScaleByHalf?2.0f:1.0f; + + TextureConversionShader::SetShaderParameters((float)expandedWidth, + expandedHeight * MValueY, + source.left * MValueX, + top, + sampleStride * MValueX, + sampleStride * MValueY); + + TargetRectangle scaledSource; + scaledSource.top = 0; + scaledSource.bottom = expandedHeight; + scaledSource.left = 0; + scaledSource.right = expandedWidth / samples; + + + int cacheBytes = 32; + if ((format & 0x0f) == 6) + cacheBytes = 64; + + int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); + g_renderer->ResetAPIState(); + EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0); + FramebufferManager::SetFramebuffer(0); + VertexShaderManager::SetViewportChanged(); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureCache::DisableStage(0); + g_renderer->RestoreAPIState(); + GL_REPORT_ERRORD(); +} + + +u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY,bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) +{ + u32 format = copyfmt; + + if (bFromZBuffer) + { + format |= _GX_TF_ZTF; + if (copyfmt == 11) + format = GX_TF_Z16; + else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) + format |= _GX_TF_CTF; + } + else + if (copyfmt > GX_TF_RGBA8 || (copyfmt < GX_TF_RGB565 && !bIsIntensityFmt)) + format |= _GX_TF_CTF; + + FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format); + if (texconv_shader.glprogid == 0) + return 0; + + u8 *dest_ptr = Memory_GetPtr(address); + + int width = (source.right - source.left) >> bScaleByHalf; + int height = (source.bottom - source.top) >> bScaleByHalf; + + int size_in_bytes = TexDecoder_GetTextureSizeInBytes(width, height, format); + + u16 blkW = TexDecoder_GetBlockWidthInTexels(format) - 1; + u16 blkH = TexDecoder_GetBlockHeightInTexels(format) - 1; + u16 samples = TextureConversionShader::GetEncodedSampleCount(format); + + // only copy on cache line boundaries + // extra pixels are copied but not displayed in the resulting texture + s32 expandedWidth = (width + blkW) & (~blkW); + s32 expandedHeight = (height + blkH) & (~blkH); + + float sampleStride = bScaleByHalf?2.0f:1.0f; + float top = (EFB_HEIGHT - source.top - expandedHeight) * MValueY ; + TextureConversionShader::SetShaderParameters((float)expandedWidth, + expandedHeight * MValueY, + source.left * MValueX, + top, + sampleStride * MValueX, + sampleStride * MValueY); + + TargetRectangle scaledSource; + scaledSource.top = 0; + scaledSource.bottom = expandedHeight; + scaledSource.left = 0; + scaledSource.right = expandedWidth / samples; + + + int cacheBytes = 32; + if ((format & 0x0f) == 6) + cacheBytes = 64; + + int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); + + EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight, readStride, true, bScaleByHalf > 0 && !bFromZBuffer); + g_texture_cache->MakeRangeDynamic(address,size_in_bytes); + return GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples); +} + +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight) +{ + g_renderer->ResetAPIState(); + EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); + FramebufferManager::SetFramebuffer(0); + VertexShaderManager::SetViewportChanged(); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + TextureCache::DisableStage(0); + g_renderer->RestoreAPIState(); + GL_REPORT_ERRORD(); +} + + +// Should be scale free. +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) +{ + u8* srcAddr = Memory_GetPtr(xfbAddr); + if (!srcAddr) + { + WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); + return; + } + + g_renderer->ResetAPIState(); + + int srcFmtWidth = srcWidth / 2; + + // swich to texture converter frame buffer + // attach destTexture as color destination + FramebufferManager::SetFramebuffer(s_texConvFrameBuffer); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0); + + GL_REPORT_FBO_ERROR(); + + for (int i = 1; i < 8; ++i) + TextureCache::DisableStage(i); + + // activate source texture + // set srcAddr as data for source texture + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_RECTANGLE_ARB); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); + + // TODO: make this less slow. (How?) + if((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight) + { + glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,0,0,s_srcTextureWidth, s_srcTextureHeight, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); + } + else + { + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); + s_srcTextureWidth = (GLsizei)srcFmtWidth; + s_srcTextureHeight = (GLsizei)srcHeight; + } + + glViewport(0, 0, srcWidth, srcHeight); + + PixelShaderCache::SetCurrentShader(s_yuyvToRgbProgram.glprogid); + + GL_REPORT_ERRORD(); + + glBegin(GL_QUADS); + glTexCoord2f((float)srcFmtWidth, (float)srcHeight); + glVertex2f(1, -1); + glTexCoord2f((float)srcFmtWidth, 0); + glVertex2f(1, 1); + glTexCoord2f(0, 0); + glVertex2f(-1, 1); + glTexCoord2f(0, (float)srcHeight); + glVertex2f(-1, -1); + glEnd(); + + // reset state + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + TextureCache::DisableStage(0); + + VertexShaderManager::SetViewportChanged(); + + FramebufferManager::SetFramebuffer(0); + + g_renderer->RestoreAPIState(); + GL_REPORT_ERRORD(); +} + +} // namespace + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.h index 650d50640f..15dd2f795b 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_TextureConverter.h @@ -1,50 +1,50 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_TEXTURECONVERTER_H_ -#define _OGL_TEXTURECONVERTER_H_ - -#include "VideoCommon.h" - -#include "OGL_GLUtil.h" - -namespace OGL -{ - -// Converts textures between formats -// TODO: support multiple texture formats -namespace TextureConverter -{ - -void Init(); -void Shutdown(); - -void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, - u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); - -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight); - -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); - -u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); - -} - -} - -#endif // _TEXTURECONVERTER_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_TEXTURECONVERTER_H_ +#define _OGL_TEXTURECONVERTER_H_ + +#include "VideoCommon.h" + +#include "OGL_GLUtil.h" + +namespace OGL +{ + +// Converts textures between formats +// TODO: support multiple texture formats +namespace TextureConverter +{ + +void Init(); +void Shutdown(); + +void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, + u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); + +void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight); + +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); + +u64 EncodeToRamFromTexture(u32 address,GLuint source_texture,float MValueX,float MValueY, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); + +} + +} + +#endif // _TEXTURECONVERTER_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.cpp index 30397b89b2..7e53f4c281 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.cpp @@ -1,113 +1,113 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include -#include - -// Common -#include "MemoryUtil.h" -#include "FileUtil.h" - -// VideoCommon -#include "Fifo.h" -#include "VideoConfig.h" -#include "Statistics.h" -#include "Profiler.h" -#include "ImageWrite.h" -#include "BPMemory.h" -#include "IndexGenerator.h" -#include "OpcodeDecoding.h" -#include "PixelShaderManager.h" -#include "VertexShaderManager.h" -#include "VertexShaderGen.h" -#include "VertexLoader.h" - -// OGL -#include "OGL_Render.h" -#include "OGL_TextureCache.h" -#include "OGL_PixelShaderCache.h" -#include "OGL_VertexShaderCache.h" -#include "OGL_VertexManager.h" - -#include "../Main.h" - -namespace OGL -{ - -enum -{ - MAXVBUFFERSIZE = 0x1FFFF, - MAXIBUFFERSIZE = 0xFFFF, - MAXVBOBUFFERCOUNT = 0x8, -}; - -//static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0}; -//static int s_nCurVBOIndex = 0; // current free buffer - -VertexManager::VertexManager() -{ - lastPrimitive = GX_DRAW_NONE; - - //s_nCurVBOIndex = 0; - //glGenBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers); - glEnableClientState(GL_VERTEX_ARRAY); - g_nativeVertexFmt = NULL; - - GL_REPORT_ERRORD(); -} - -VertexManager::~VertexManager() -{ - //glDeleteBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers); - //s_nCurVBOIndex = 0; -} - -void VertexManager::Draw(u32 /*stride*/, bool alphapass) -{ - if (alphapass) - { - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glDisable(GL_BLEND); - } - - if (IndexGenerator::GetNumTriangles() > 0) - { - glDrawElements(GL_TRIANGLES, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT, TIBuffer); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumLines() > 0) - { - glDrawElements(GL_LINES, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT, LIBuffer); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - if (IndexGenerator::GetNumPoints() > 0) - { - glDrawElements(GL_POINTS, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT, PIBuffer); - INCSTAT(stats.thisFrame.numIndexedDrawCalls); - } - - if (alphapass) - { - // restore color mask - g_renderer->SetColorMask(); - - if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract) - glEnable(GL_BLEND); - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include +#include + +// Common +#include "MemoryUtil.h" +#include "FileUtil.h" + +// VideoCommon +#include "Fifo.h" +#include "VideoConfig.h" +#include "Statistics.h" +#include "Profiler.h" +#include "ImageWrite.h" +#include "BPMemory.h" +#include "IndexGenerator.h" +#include "OpcodeDecoding.h" +#include "PixelShaderManager.h" +#include "VertexShaderManager.h" +#include "VertexShaderGen.h" +#include "VertexLoader.h" + +// OGL +#include "OGL_Render.h" +#include "OGL_TextureCache.h" +#include "OGL_PixelShaderCache.h" +#include "OGL_VertexShaderCache.h" +#include "OGL_VertexManager.h" + +#include "../Main.h" + +namespace OGL +{ + +enum +{ + MAXVBUFFERSIZE = 0x1FFFF, + MAXIBUFFERSIZE = 0xFFFF, + MAXVBOBUFFERCOUNT = 0x8, +}; + +//static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0}; +//static int s_nCurVBOIndex = 0; // current free buffer + +VertexManager::VertexManager() +{ + lastPrimitive = GX_DRAW_NONE; + + //s_nCurVBOIndex = 0; + //glGenBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers); + glEnableClientState(GL_VERTEX_ARRAY); + g_nativeVertexFmt = NULL; + + GL_REPORT_ERRORD(); +} + +VertexManager::~VertexManager() +{ + //glDeleteBuffers(ARRAYSIZE(s_vboBuffers), s_vboBuffers); + //s_nCurVBOIndex = 0; +} + +void VertexManager::Draw(u32 /*stride*/, bool alphapass) +{ + if (alphapass) + { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + glDisable(GL_BLEND); + } + + if (IndexGenerator::GetNumTriangles() > 0) + { + glDrawElements(GL_TRIANGLES, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT, TIBuffer); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumLines() > 0) + { + glDrawElements(GL_LINES, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT, LIBuffer); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + if (IndexGenerator::GetNumPoints() > 0) + { + glDrawElements(GL_POINTS, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT, PIBuffer); + INCSTAT(stats.thisFrame.numIndexedDrawCalls); + } + + if (alphapass) + { + // restore color mask + g_renderer->SetColorMask(); + + if (bpmem.blendmode.blendenable || bpmem.blendmode.subtract) + glEnable(GL_BLEND); + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.h index 0bd63a3e86..a1039cc9dc 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexManager.h @@ -1,44 +1,44 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_VERTEXMANAGER_H_ -#define _OGL_VERTEXMANAGER_H_ - -#include "CPMemory.h" -#include "NativeVertexWriter.h" - -#include "../VertexManager.h" - -namespace OGL -{ - -// Handles the OpenGL details of drawing lots of vertices quickly. -// Other functionality is moving out. -class VertexManager : public ::VertexManagerBase -{ -public: - VertexManager(); - ~VertexManager(); - - void Draw(u32 stride, bool alphapass); - - NativeVertexFormat* CreateNativeVertexFormat(); -}; - -} - -#endif // _VERTEXMANAGER_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_VERTEXMANAGER_H_ +#define _OGL_VERTEXMANAGER_H_ + +#include "CPMemory.h" +#include "NativeVertexWriter.h" + +#include "../VertexManager.h" + +namespace OGL +{ + +// Handles the OpenGL details of drawing lots of vertices quickly. +// Other functionality is moving out. +class VertexManager : public ::VertexManagerBase +{ +public: + VertexManager(); + ~VertexManager(); + + void Draw(u32 stride, bool alphapass); + + NativeVertexFormat* CreateNativeVertexFormat(); +}; + +} + +#endif // _VERTEXMANAGER_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.cpp index e28283f2f3..9f324b105a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.cpp @@ -1,255 +1,255 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include - -// Common -#include "FileUtil.h" - -// VideoCommon -#include "Profiler.h" -#include "VideoConfig.h" -#include "Statistics.h" -#include "VertexShaderGen.h" -#include "VertexShaderManager.h" -#include "VertexLoader.h" -#include "XFMemory.h" -#include "ImageWrite.h" - -// OGL -#include "OGL_Render.h" -#include "OGL_VertexShaderCache.h" -#include "OGL_GLUtil.h" -#include "OGL_VertexManager.h" - -#include "../Main.h" - -namespace OGL -{ - -VertexShaderCache::VSCache VertexShaderCache::vshaders; -bool VertexShaderCache::s_displayCompileAlert; -GLuint VertexShaderCache::CurrentShader; -bool VertexShaderCache::ShaderEnabled; - -static VERTEXSHADER *pShaderLast = NULL; -static int s_nMaxVertexInstructions; - -void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - float f[4] = { f1, f2, f3, f4 }; - glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); -} - -void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f) -{ - glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); -} - -void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f) -{ - for (unsigned int i = 0; i < count; i++,f+=4) - glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f); -} - -void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f) -{ - for (unsigned int i = 0; i < count; i++) - { - float buf[4]; - buf[0] = *f++; - buf[1] = *f++; - buf[2] = *f++; - buf[3] = 0.f; - glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, buf); - } -} - - -VertexShaderCache::VertexShaderCache() -{ - glEnable(GL_VERTEX_PROGRAM_ARB); - ShaderEnabled = true; - CurrentShader = 0; - memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); - - s_displayCompileAlert = true; - - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions); -#if CG_VERSION_NUM == 2100 - if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL) - { - s_nMaxVertexInstructions = 4096; - } -#endif -} - -VertexShaderCache::~VertexShaderCache() -{ - for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++) - iter->second.Destroy(); - vshaders.clear(); -} - -bool VertexShaderCache::SetShader(u32 components) -{ - const VERTEXSHADER* const vs = GetShader(components); - if (vs) - { - SetCurrentShader(vs->glprogid); - return true; - } - else - return false; -} - -VERTEXSHADER* VertexShaderCache::GetShader(u32 components) -{ - DVSTARTPROFILE(); - VERTEXSHADERUID uid; - GetVertexShaderId(&uid, components); - - if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) - { - return pShaderLast; - } - memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); - - VSCache::iterator iter = vshaders.find(uid); - - if (iter != vshaders.end()) { - iter->second.frameCount = frameCount; - VSCacheEntry &entry = iter->second; - if (&entry.shader != pShaderLast) { - pShaderLast = &entry.shader; - } - - return pShaderLast; - } - - //Make an entry in the table - VSCacheEntry& entry = vshaders[uid]; - entry.frameCount = frameCount; - pShaderLast = &entry.shader; - const char *code = GenerateVertexShaderCode(components, API_OPENGL); - -#if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { - static int counter = 0; - char szTemp[MAX_PATH]; - sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); - - SaveData(szTemp, code); - } -#endif - - if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) { - ERROR_LOG(VIDEO, "failed to create vertex shader"); - return NULL; - } - - INCSTAT(stats.numVertexShadersCreated); - SETSTAT(stats.numVertexShadersAlive, vshaders.size()); - return pShaderLast; -} - -bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram) -{ - // Reset GL error before compiling shaders. Yeah, we need to investigate the causes of these. - GLenum err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) - { - ERROR_LOG(VIDEO, "glError %08x before VS!", err); - } - -#if defined HAVE_CG && HAVE_CG - char stropt[64]; - sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions); - const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; - CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts); - if (!cgIsProgram(tempprog)) { - if (s_displayCompileAlert) { - PanicAlert("Failed to create vertex shader"); - s_displayCompileAlert = false; - } - cgDestroyProgram(tempprog); - ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext)); - ERROR_LOG(VIDEO, pstrprogram); - return false; - } - - if (cgGetError() != CG_NO_ERROR) - { - WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext)); - WARN_LOG(VIDEO, pstrprogram); - } - - // This looks evil - we modify the program through the const char * we got from cgGetProgramString! - // It SHOULD not have any nasty side effects though - but you never know... - char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); - char *plocal = strstr(pcompiledprog, "program.local"); - while (plocal != NULL) { - const char* penv = " program.env"; - memcpy(plocal, penv, 13); - plocal = strstr(plocal + 13, "program.local"); - } - glGenProgramsARB(1, &vs.glprogid); - SetCurrentShader(vs.glprogid); - - glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); - err = GL_REPORT_ERROR(); - if (err != GL_NO_ERROR) { - ERROR_LOG(VIDEO, pstrprogram); - ERROR_LOG(VIDEO, pcompiledprog); - } - - cgDestroyProgram(tempprog); -#endif - -#if defined(_DEBUG) || defined(DEBUGFAST) - vs.strprog = pstrprogram; -#endif - - return true; -} - -void VertexShaderCache::DisableShader() -{ - if (ShaderEnabled) - { - glDisable(GL_VERTEX_PROGRAM_ARB); - ShaderEnabled = false; - } -} - - -void VertexShaderCache::SetCurrentShader(GLuint Shader) -{ - if (!ShaderEnabled) - { - glEnable(GL_VERTEX_PROGRAM_ARB); - ShaderEnabled= true; - } - if (CurrentShader != Shader) - { - if(Shader != 0) - CurrentShader = Shader; - glBindProgramARB(GL_VERTEX_PROGRAM_ARB, CurrentShader); - } -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include + +// Common +#include "FileUtil.h" + +// VideoCommon +#include "Profiler.h" +#include "VideoConfig.h" +#include "Statistics.h" +#include "VertexShaderGen.h" +#include "VertexShaderManager.h" +#include "VertexLoader.h" +#include "XFMemory.h" +#include "ImageWrite.h" + +// OGL +#include "OGL_Render.h" +#include "OGL_VertexShaderCache.h" +#include "OGL_GLUtil.h" +#include "OGL_VertexManager.h" + +#include "../Main.h" + +namespace OGL +{ + +VertexShaderCache::VSCache VertexShaderCache::vshaders; +bool VertexShaderCache::s_displayCompileAlert; +GLuint VertexShaderCache::CurrentShader; +bool VertexShaderCache::ShaderEnabled; + +static VERTEXSHADER *pShaderLast = NULL; +static int s_nMaxVertexInstructions; + +void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + float f[4] = { f1, f2, f3, f4 }; + glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); +} + +void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float *f) +{ + glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f); +} + +void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f) +{ + for (unsigned int i = 0; i < count; i++,f+=4) + glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f); +} + +void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f) +{ + for (unsigned int i = 0; i < count; i++) + { + float buf[4]; + buf[0] = *f++; + buf[1] = *f++; + buf[2] = *f++; + buf[3] = 0.f; + glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, buf); + } +} + + +VertexShaderCache::VertexShaderCache() +{ + glEnable(GL_VERTEX_PROGRAM_ARB); + ShaderEnabled = true; + CurrentShader = 0; + memset(&last_vertex_shader_uid, 0xFF, sizeof(last_vertex_shader_uid)); + + s_displayCompileAlert = true; + + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions); +#if CG_VERSION_NUM == 2100 + if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL) + { + s_nMaxVertexInstructions = 4096; + } +#endif +} + +VertexShaderCache::~VertexShaderCache() +{ + for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); iter++) + iter->second.Destroy(); + vshaders.clear(); +} + +bool VertexShaderCache::SetShader(u32 components) +{ + const VERTEXSHADER* const vs = GetShader(components); + if (vs) + { + SetCurrentShader(vs->glprogid); + return true; + } + else + return false; +} + +VERTEXSHADER* VertexShaderCache::GetShader(u32 components) +{ + DVSTARTPROFILE(); + VERTEXSHADERUID uid; + GetVertexShaderId(&uid, components); + + if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) + { + return pShaderLast; + } + memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); + + VSCache::iterator iter = vshaders.find(uid); + + if (iter != vshaders.end()) { + iter->second.frameCount = frameCount; + VSCacheEntry &entry = iter->second; + if (&entry.shader != pShaderLast) { + pShaderLast = &entry.shader; + } + + return pShaderLast; + } + + //Make an entry in the table + VSCacheEntry& entry = vshaders[uid]; + entry.frameCount = frameCount; + pShaderLast = &entry.shader; + const char *code = GenerateVertexShaderCode(components, API_OPENGL); + +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX), counter++); + + SaveData(szTemp, code); + } +#endif + + if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) { + ERROR_LOG(VIDEO, "failed to create vertex shader"); + return NULL; + } + + INCSTAT(stats.numVertexShadersCreated); + SETSTAT(stats.numVertexShadersAlive, vshaders.size()); + return pShaderLast; +} + +bool VertexShaderCache::CompileVertexShader(VERTEXSHADER& vs, const char* pstrprogram) +{ + // Reset GL error before compiling shaders. Yeah, we need to investigate the causes of these. + GLenum err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) + { + ERROR_LOG(VIDEO, "glError %08x before VS!", err); + } + +#if defined HAVE_CG && HAVE_CG + char stropt[64]; + sprintf(stropt, "MaxLocalParams=256,MaxInstructions=%d", s_nMaxVertexInstructions); + const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL}; + CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgvProf, "main", opts); + if (!cgIsProgram(tempprog)) { + if (s_displayCompileAlert) { + PanicAlert("Failed to create vertex shader"); + s_displayCompileAlert = false; + } + cgDestroyProgram(tempprog); + ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext)); + ERROR_LOG(VIDEO, pstrprogram); + return false; + } + + if (cgGetError() != CG_NO_ERROR) + { + WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext)); + WARN_LOG(VIDEO, pstrprogram); + } + + // This looks evil - we modify the program through the const char * we got from cgGetProgramString! + // It SHOULD not have any nasty side effects though - but you never know... + char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM); + char *plocal = strstr(pcompiledprog, "program.local"); + while (plocal != NULL) { + const char* penv = " program.env"; + memcpy(plocal, penv, 13); + plocal = strstr(plocal + 13, "program.local"); + } + glGenProgramsARB(1, &vs.glprogid); + SetCurrentShader(vs.glprogid); + + glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog); + err = GL_REPORT_ERROR(); + if (err != GL_NO_ERROR) { + ERROR_LOG(VIDEO, pstrprogram); + ERROR_LOG(VIDEO, pcompiledprog); + } + + cgDestroyProgram(tempprog); +#endif + +#if defined(_DEBUG) || defined(DEBUGFAST) + vs.strprog = pstrprogram; +#endif + + return true; +} + +void VertexShaderCache::DisableShader() +{ + if (ShaderEnabled) + { + glDisable(GL_VERTEX_PROGRAM_ARB); + ShaderEnabled = false; + } +} + + +void VertexShaderCache::SetCurrentShader(GLuint Shader) +{ + if (!ShaderEnabled) + { + glEnable(GL_VERTEX_PROGRAM_ARB); + ShaderEnabled= true; + } + if (CurrentShader != Shader) + { + if(Shader != 0) + CurrentShader = Shader; + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, CurrentShader); + } +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.h index 013cf96424..b12c166cd6 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_VertexShaderCache.h @@ -1,89 +1,89 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_VERTEXSHADERCACHE_H_ -#define _OGL_VERTEXSHADERCACHE_H_ - -#include -#include - -// VideoCommon -#include "BPMemory.h" -#include "VertexShaderGen.h" - -// OGL -#include "OGL_GLUtil.h" - -#include "../VertexShaderCache.h" - -namespace OGL -{ - -struct VERTEXSHADER -{ - VERTEXSHADER() : glprogid(0) {} - GLuint glprogid; // opengl program id - -#if defined(_DEBUG) || defined(DEBUGFAST) - std::string strprog; -#endif -}; - -class VertexShaderCache : public ::VertexShaderCacheBase -{ - struct VSCacheEntry - { - VERTEXSHADER shader; - int frameCount; - VSCacheEntry() : frameCount(0) {} - void Destroy() { - // printf("Destroying vs %i\n", shader.glprogid); - glDeleteProgramsARB(1, &shader.glprogid); - shader.glprogid = 0; - } - }; - - typedef std::map VSCache; - - static VSCache vshaders; - - static bool s_displayCompileAlert; - - static GLuint CurrentShader; - static bool ShaderEnabled; - -public: - VertexShaderCache(); - ~VertexShaderCache(); - - bool SetShader(u32 components); - - static VERTEXSHADER* GetShader(u32 components); - static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram); - - static void SetCurrentShader(GLuint Shader); - static void DisableShader(); - - void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); - void SetVSConstant4fv(unsigned int const_number, const float* f); - void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f); - void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f); -}; - -} - -#endif // _VERTEXSHADERCACHE_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_VERTEXSHADERCACHE_H_ +#define _OGL_VERTEXSHADERCACHE_H_ + +#include +#include + +// VideoCommon +#include "BPMemory.h" +#include "VertexShaderGen.h" + +// OGL +#include "OGL_GLUtil.h" + +#include "../VertexShaderCache.h" + +namespace OGL +{ + +struct VERTEXSHADER +{ + VERTEXSHADER() : glprogid(0) {} + GLuint glprogid; // opengl program id + +#if defined(_DEBUG) || defined(DEBUGFAST) + std::string strprog; +#endif +}; + +class VertexShaderCache : public ::VertexShaderCacheBase +{ + struct VSCacheEntry + { + VERTEXSHADER shader; + int frameCount; + VSCacheEntry() : frameCount(0) {} + void Destroy() { + // printf("Destroying vs %i\n", shader.glprogid); + glDeleteProgramsARB(1, &shader.glprogid); + shader.glprogid = 0; + } + }; + + typedef std::map VSCache; + + static VSCache vshaders; + + static bool s_displayCompileAlert; + + static GLuint CurrentShader; + static bool ShaderEnabled; + +public: + VertexShaderCache(); + ~VertexShaderCache(); + + bool SetShader(u32 components); + + static VERTEXSHADER* GetShader(u32 components); + static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram); + + static void SetCurrentShader(GLuint Shader); + static void DisableShader(); + + void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4); + void SetVSConstant4fv(unsigned int const_number, const float* f); + void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f); + void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f); +}; + +} + +#endif // _VERTEXSHADERCACHE_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.cpp b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.cpp index bc859d37b3..b3c511dd09 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.cpp @@ -1,42 +1,42 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - - -// ---------------------------------------------------------------------------------------------------------- -// This file handles the External Frame Buffer (XFB). The XFB is a storage point when the picture is resized -// by the system to the correct display format for output to the TV. In most cases its function can be -// supplemented by the equivalent adjustments in glScissor and glViewport (or their DirectX equivalents). But -// for some homebrew games these functions are necessary because the homebrew game communicate directly with -// them. -// ---------------------------------------------------------------------------------------------------------- - -// OGL -#include "OGL_Render.h" -#include "OGL_TextureConverter.h" -#include "OGL_FramebufferManager.h" -#include "OGL_XFB.h" - -namespace OGL -{ - -void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt) -{ - TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); - TextureConverter::EncodeToRamYUYV(FramebufferManager::ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, dstWd, dstHt); -} - -} +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + + +// ---------------------------------------------------------------------------------------------------------- +// This file handles the External Frame Buffer (XFB). The XFB is a storage point when the picture is resized +// by the system to the correct display format for output to the TV. In most cases its function can be +// supplemented by the equivalent adjustments in glScissor and glViewport (or their DirectX equivalents). But +// for some homebrew games these functions are necessary because the homebrew game communicate directly with +// them. +// ---------------------------------------------------------------------------------------------------------- + +// OGL +#include "OGL_Render.h" +#include "OGL_TextureConverter.h" +#include "OGL_FramebufferManager.h" +#include "OGL_XFB.h" + +namespace OGL +{ + +void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt) +{ + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); + TextureConverter::EncodeToRamYUYV(FramebufferManager::ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, dstWd, dstHt); +} + +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.h b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.h index a04d6f18af..e28c30448b 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_XFB.h @@ -1,31 +1,31 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _OGL_XFB_H_ -#define _OGL_XFB_H_ - -#include "OGL_GLUtil.h" - -namespace OGL -{ - -// write the EFB to the XFB -void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt); - -} - -#endif // _XFB_H_ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _OGL_XFB_H_ +#define _OGL_XFB_H_ + +#include "OGL_GLUtil.h" + +namespace OGL +{ + +// write the EFB to the XFB +void XFB_Write(u8 *xfb_in_ram, const EFBRectangle& sourceRc, u32 dstWd, u32 dstHt); + +} + +#endif // _XFB_H_ diff --git a/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.cpp index 207f131883..9f84d57ffd 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.cpp @@ -1,20 +1,20 @@ - -#include "PixelShaderManager.h" - -#include "Main.h" -#include "PixelShaderCache.h" - -void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - g_pixel_shader_cache->SetPSConstant4f(const_number, f1, f2, f3, f4); -} - -void SetPSConstant4fv(unsigned int const_number, const float *f) -{ - g_pixel_shader_cache->SetPSConstant4fv(const_number, f); -} - -void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) -{ - g_pixel_shader_cache->SetMultiPSConstant4fv(const_number, count, f); -} + +#include "PixelShaderManager.h" + +#include "Main.h" +#include "PixelShaderCache.h" + +void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + g_pixel_shader_cache->SetPSConstant4f(const_number, f1, f2, f3, f4); +} + +void SetPSConstant4fv(unsigned int const_number, const float *f) +{ + g_pixel_shader_cache->SetPSConstant4fv(const_number, f); +} + +void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) +{ + g_pixel_shader_cache->SetMultiPSConstant4fv(const_number, count, f); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.h index 4dcc510cfb..6e375da781 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/PixelShaderCache.h @@ -1,20 +1,20 @@ - -#ifndef _PIXELSHADERCACHE_H_ -#define _PIXELSHADERCACHE_H_ - -class PixelShaderCacheBase -{ -public: - virtual ~PixelShaderCacheBase() {} - - virtual bool SetShader(bool dstAlphaEnable) = 0; - - virtual void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0; - virtual void SetPSConstant4fv(unsigned int const_number, const float *f) = 0; - virtual void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) = 0; - -protected: - -}; - -#endif + +#ifndef _PIXELSHADERCACHE_H_ +#define _PIXELSHADERCACHE_H_ + +class PixelShaderCacheBase +{ +public: + virtual ~PixelShaderCacheBase() {} + + virtual bool SetShader(bool dstAlphaEnable) = 0; + + virtual void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0; + virtual void SetPSConstant4fv(unsigned int const_number, const float *f) = 0; + virtual void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f) = 0; + +protected: + +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/Renderer.cpp b/Source/Plugins/Plugin_VideoMerge/Src/Renderer.cpp index 1779e0be53..9c648c4d8d 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/Renderer.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/Renderer.cpp @@ -1,390 +1,390 @@ - -#include - -#include "Common.h" -#include "Timer.h" - -#include "Render.h" -#include "BPMemory.h" -#include "Atomic.h" -#include "VideoConfig.h" -#include "FramebufferManager.h" - -#include "Fifo.h" -#include "VertexShaderManager.h" -#include "DLCache.h" -#include "OnScreenDisplay.h" -#include "Statistics.h" - -#include "Renderer.h" - -#include "Main.h" - -int RendererBase::s_target_width; -int RendererBase::s_target_height; - -int RendererBase::s_Fulltarget_width; -int RendererBase::s_Fulltarget_height; - -int RendererBase::s_backbuffer_width; -int RendererBase::s_backbuffer_height; - -int RendererBase::s_XFB_width; -int RendererBase::s_XFB_height; - -float RendererBase::xScale; -float RendererBase::yScale; - -int RendererBase::s_fps; - -u32 RendererBase::s_blendMode; -bool RendererBase::XFBWrited; - -float RendererBase::EFBxScale; -float RendererBase::EFByScale; - -volatile u32 RendererBase::s_swapRequested; - -//void VideoConfig::UpdateProjectionHack() -//{ -// return; -// //::UpdateProjectionHack(g_Config.iPhackvalue); -//} - -RendererBase::RendererBase() -{ - UpdateActiveConfig(); - s_blendMode = 0; - - s_XFB_width = MAX_XFB_WIDTH; - s_XFB_height = MAX_XFB_HEIGHT; -} - -// can maybe reuse this func in Renderer::Swap to eliminate redundant code -void RendererBase::FramebufferSize(int w, int h) -{ - TargetRectangle dst_rect; - ComputeDrawRectangle(w, h, false, &dst_rect); - - xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width; - yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height; - - // TODO: why these, prolly can remove them - const int s_LastAA = g_ActiveConfig.iMultisampleMode; - const int s_LastEFBScale = g_ActiveConfig.iEFBScale; - - switch (s_LastEFBScale) - { - case 0: - EFBxScale = xScale; - EFByScale = yScale; - break; - - case 1: - EFBxScale = ceilf(xScale); - EFByScale = ceilf(yScale); - break; - - default: - EFByScale = EFBxScale = (g_ActiveConfig.iEFBScale - 1); - break; - }; - - const float SupersampleCoeficient = s_LastAA + 1; - EFBxScale *= SupersampleCoeficient; - EFByScale *= SupersampleCoeficient; - - s_target_width = (int)(EFB_WIDTH * EFBxScale); - s_target_height = (int)(EFB_HEIGHT * EFByScale); - - // TODO: set anything else? - s_Fulltarget_width = s_target_width; - s_Fulltarget_height = s_target_height; -} - -void UpdateViewport() -{ - g_renderer->UpdateViewport(); -} - -void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - RendererBase::RenderToXFB(xfbAddr, fbWidth, fbHeight, sourceRc); -} - -// whats this for? -bool IsD3D() -{ - //PanicAlert("IsD3D!"); - // TODO: temporary - return true; -} - -void Renderer::RenderText(const char *pstr, int left, int top, u32 color) -{ - -} - -void RendererBase::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) -{ - if (!fbWidth || !fbHeight) - return; - - VideoFifo_CheckEFBAccess(); - VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight); - XFBWrited = true; - - // XXX: Without the VI, how would we know what kind of field this is? So - // just use progressive. - - if (g_ActiveConfig.bUseXFB) - { - g_framebuffer_manager->CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc); - } - else - { - g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight, sourceRc); - Common::AtomicStoreRelease(s_swapRequested, FALSE); - } -} - -TargetRectangle RendererBase::ConvertEFBRectangle(const EFBRectangle& rc) -{ - int Xstride = (s_Fulltarget_width - s_target_width) / 2; - int Ystride = (s_Fulltarget_height - s_target_height) / 2; - TargetRectangle result; - result.left = (int)(rc.left * EFBxScale) + Xstride; - result.top = (int)(rc.top * EFByScale) + Ystride; - result.right = (int)(rc.right * EFBxScale) + Xstride; - result.bottom = (int)(rc.bottom * EFByScale) + Ystride; - return result; -} - -bool RendererBase::SetScissorRect(EFBRectangle &rc) -{ - int xoff = bpmem.scissorOffset.x * 2 - 342; - int yoff = bpmem.scissorOffset.y * 2 - 342; - - rc.left = bpmem.scissorTL.x - xoff - 342; - rc.top = bpmem.scissorTL.y - yoff - 342; - rc.right = bpmem.scissorBR.x - xoff - 341; - rc.bottom = bpmem.scissorBR.y - yoff - 341; - - int Xstride = (s_Fulltarget_width - s_target_width) / 2; - int Ystride = (s_Fulltarget_height - s_target_height) / 2; - - rc.left = (int)(rc.left * EFBxScale); - rc.top = (int)(rc.top * EFByScale); - rc.right = (int)(rc.right * EFBxScale); - rc.bottom = (int)(rc.bottom * EFByScale); - - if (rc.left < 0) rc.left = 0; - if (rc.right < 0) rc.right = 0; - if (rc.left > s_target_width) rc.left = s_target_width; - if (rc.right > s_target_width) rc.right = s_target_width; - if (rc.top < 0) rc.top = 0; - if (rc.bottom < 0) rc.bottom = 0; - if (rc.top > s_target_height) rc.top = s_target_height; - if (rc.bottom > s_target_height) rc.bottom = s_target_height; - - rc.left += Xstride; - rc.top += Ystride; - rc.right += Xstride; - rc.bottom += Ystride; - - if (rc.left > rc.right) - { - int temp = rc.right; - rc.right = rc.left; - rc.left = temp; - } - if (rc.top > rc.bottom) - { - int temp = rc.bottom; - rc.bottom = rc.top; - rc.top = temp; - } - - return (rc.right >= rc.left && rc.bottom >= rc.top); -} - -void RendererBase::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc) -{ - if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.bUseRealXFB) || !fbWidth || !fbHeight) - { - g_VideoInitialize.pCopiedToXFB(false); - return; - } - - // this function is called after the XFB field is changed, not after - // EFB is copied to XFB. In this way, flickering is reduced in games - // and seems to also give more FPS in ZTP - - if (field == FIELD_LOWER) - xfbAddr -= fbWidth * 2; - u32 xfbCount = 0; - const XFBSourceBase** xfbSourceList = g_framebuffer_manager->GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); - - if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - g_VideoInitialize.pCopiedToXFB(false); - return; - } - - g_renderer->ResetAPIState(); - - // prepare copying the XFBs to our backbuffer - TargetRectangle dst_rect; - ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); - - g_renderer->PrepareXFBCopy(dst_rect); - - if (g_ActiveConfig.bUseXFB) - { - const XFBSourceBase* xfbSource; - - // draw each xfb source - for (u32 i = 0; i < xfbCount; ++i) - { - xfbSource = xfbSourceList[i]; - TargetRectangle sourceRc; - - //if (g_ActiveConfig.bAutoScale) - //{ - // sourceRc = xfbSource->sourceRc; - //} - //else - //{ - sourceRc.left = 0; - sourceRc.top = 0; - sourceRc.right = xfbSource->texWidth; - sourceRc.bottom = xfbSource->texHeight; - //} - - MathUtil::Rectangle drawRc; - - if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2); - - drawRc.bottom = 1.0f - 2.0f * ((hOffset) / (float)fbHeight); - drawRc.top = 1.0f - 2.0f * ((hOffset + xfbHeight) / (float)fbHeight); - drawRc.left = -(xfbWidth / (float)fbWidth); - drawRc.right = (xfbWidth / (float)fbWidth); - - if (!g_ActiveConfig.bAutoScale) - { - // scale draw area for a 1 to 1 pixel mapping with the draw target - float vScale = (float)fbHeight / (float)s_backbuffer_height; - float hScale = (float)fbWidth / (float)s_backbuffer_width; - - drawRc.top *= vScale; - drawRc.bottom *= vScale; - drawRc.left *= hScale; - drawRc.right *= hScale; - } - } - else - { - drawRc.top = -1; - drawRc.bottom = 1; - drawRc.left = -1; - drawRc.right = 1; - } - - g_renderer->Draw(xfbSource, sourceRc, drawRc, rc); - } - } - else - { - // TODO: organize drawRc stuff - MathUtil::Rectangle drawRc; - drawRc.top = -1; - drawRc.bottom = 1; - drawRc.left = -1; - drawRc.right = 1; - - const TargetRectangle targetRc = ConvertEFBRectangle(rc); - g_renderer->Draw(NULL, targetRc, drawRc, rc); - } - - // done with drawing the game stuff, good moment to save a screenshot - // TODO: screenshot code - // - - // finally present some information - // TODO: debug text, fps, etc... - // - - OSD::DrawMessages(); - - g_renderer->EndFrame(); - - ++frameCount; - - DLCache::ProgressiveCleanup(); - g_texture_cache->Cleanup(); - - // check for configuration changes - const int last_efbscale = g_ActiveConfig.iEFBScale; - //const int last_aa = g_ActiveConfig.iMultisampleMode; - - UpdateActiveConfig(); - - - bool window_resized = g_renderer->CheckForResize(); - - bool xfbchanged = false; - if (s_XFB_width != fbWidth || s_XFB_height != fbHeight) - { - xfbchanged = true; - s_XFB_width = fbWidth; - s_XFB_height = fbHeight; - if (s_XFB_width < 1) s_XFB_width = MAX_XFB_WIDTH; - if (s_XFB_width > MAX_XFB_WIDTH) s_XFB_width = MAX_XFB_WIDTH; - if (s_XFB_height < 1) s_XFB_height = MAX_XFB_HEIGHT; - if (s_XFB_height > MAX_XFB_HEIGHT) s_XFB_height = MAX_XFB_HEIGHT; - } - - // update FPS counter - // TODO: make this better - static int fpscount = 0; - static unsigned long lasttime = 0; - if (Common::Timer::GetTimeMs() - lasttime >= 1000) - { - lasttime = Common::Timer::GetTimeMs(); - s_fps = fpscount; - fpscount = 0; - } - if (XFBWrited) - ++fpscount; - - // set default viewport and scissor, for the clear to work correctly - stats.ResetFrame(); - - // done. Show our work ;) - g_renderer->Present(); - - // resize the back buffers NOW to avoid flickering when resizing windows - if (xfbchanged || window_resized || last_efbscale != g_ActiveConfig.iEFBScale) - { - g_renderer->GetBackBufferSize(&s_backbuffer_width, &s_backbuffer_height); - - FramebufferSize(s_backbuffer_width, s_backbuffer_height); - - g_renderer->RecreateFramebufferManger(); - } - - // begin next frame - g_renderer->RestoreAPIState(); - - g_renderer->BeginFrame(); - - g_renderer->UpdateViewport(); - VertexShaderManager::SetViewportChanged(); - g_VideoInitialize.pCopiedToXFB(XFBWrited || g_ActiveConfig.bUseRealXFB); - XFBWrited = false; -} + +#include + +#include "Common.h" +#include "Timer.h" + +#include "Render.h" +#include "BPMemory.h" +#include "Atomic.h" +#include "VideoConfig.h" +#include "FramebufferManager.h" + +#include "Fifo.h" +#include "VertexShaderManager.h" +#include "DLCache.h" +#include "OnScreenDisplay.h" +#include "Statistics.h" + +#include "Renderer.h" + +#include "Main.h" + +int RendererBase::s_target_width; +int RendererBase::s_target_height; + +int RendererBase::s_Fulltarget_width; +int RendererBase::s_Fulltarget_height; + +int RendererBase::s_backbuffer_width; +int RendererBase::s_backbuffer_height; + +int RendererBase::s_XFB_width; +int RendererBase::s_XFB_height; + +float RendererBase::xScale; +float RendererBase::yScale; + +int RendererBase::s_fps; + +u32 RendererBase::s_blendMode; +bool RendererBase::XFBWrited; + +float RendererBase::EFBxScale; +float RendererBase::EFByScale; + +volatile u32 RendererBase::s_swapRequested; + +//void VideoConfig::UpdateProjectionHack() +//{ +// return; +// //::UpdateProjectionHack(g_Config.iPhackvalue); +//} + +RendererBase::RendererBase() +{ + UpdateActiveConfig(); + s_blendMode = 0; + + s_XFB_width = MAX_XFB_WIDTH; + s_XFB_height = MAX_XFB_HEIGHT; +} + +// can maybe reuse this func in Renderer::Swap to eliminate redundant code +void RendererBase::FramebufferSize(int w, int h) +{ + TargetRectangle dst_rect; + ComputeDrawRectangle(w, h, false, &dst_rect); + + xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width; + yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height; + + // TODO: why these, prolly can remove them + const int s_LastAA = g_ActiveConfig.iMultisampleMode; + const int s_LastEFBScale = g_ActiveConfig.iEFBScale; + + switch (s_LastEFBScale) + { + case 0: + EFBxScale = xScale; + EFByScale = yScale; + break; + + case 1: + EFBxScale = ceilf(xScale); + EFByScale = ceilf(yScale); + break; + + default: + EFByScale = EFBxScale = (g_ActiveConfig.iEFBScale - 1); + break; + }; + + const float SupersampleCoeficient = s_LastAA + 1; + EFBxScale *= SupersampleCoeficient; + EFByScale *= SupersampleCoeficient; + + s_target_width = (int)(EFB_WIDTH * EFBxScale); + s_target_height = (int)(EFB_HEIGHT * EFByScale); + + // TODO: set anything else? + s_Fulltarget_width = s_target_width; + s_Fulltarget_height = s_target_height; +} + +void UpdateViewport() +{ + g_renderer->UpdateViewport(); +} + +void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + RendererBase::RenderToXFB(xfbAddr, fbWidth, fbHeight, sourceRc); +} + +// whats this for? +bool IsD3D() +{ + //PanicAlert("IsD3D!"); + // TODO: temporary + return true; +} + +void Renderer::RenderText(const char *pstr, int left, int top, u32 color) +{ + +} + +void RendererBase::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + if (!fbWidth || !fbHeight) + return; + + VideoFifo_CheckEFBAccess(); + VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight); + XFBWrited = true; + + // XXX: Without the VI, how would we know what kind of field this is? So + // just use progressive. + + if (g_ActiveConfig.bUseXFB) + { + g_framebuffer_manager->CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc); + } + else + { + g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight, sourceRc); + Common::AtomicStoreRelease(s_swapRequested, FALSE); + } +} + +TargetRectangle RendererBase::ConvertEFBRectangle(const EFBRectangle& rc) +{ + int Xstride = (s_Fulltarget_width - s_target_width) / 2; + int Ystride = (s_Fulltarget_height - s_target_height) / 2; + TargetRectangle result; + result.left = (int)(rc.left * EFBxScale) + Xstride; + result.top = (int)(rc.top * EFByScale) + Ystride; + result.right = (int)(rc.right * EFBxScale) + Xstride; + result.bottom = (int)(rc.bottom * EFByScale) + Ystride; + return result; +} + +bool RendererBase::SetScissorRect(EFBRectangle &rc) +{ + int xoff = bpmem.scissorOffset.x * 2 - 342; + int yoff = bpmem.scissorOffset.y * 2 - 342; + + rc.left = bpmem.scissorTL.x - xoff - 342; + rc.top = bpmem.scissorTL.y - yoff - 342; + rc.right = bpmem.scissorBR.x - xoff - 341; + rc.bottom = bpmem.scissorBR.y - yoff - 341; + + int Xstride = (s_Fulltarget_width - s_target_width) / 2; + int Ystride = (s_Fulltarget_height - s_target_height) / 2; + + rc.left = (int)(rc.left * EFBxScale); + rc.top = (int)(rc.top * EFByScale); + rc.right = (int)(rc.right * EFBxScale); + rc.bottom = (int)(rc.bottom * EFByScale); + + if (rc.left < 0) rc.left = 0; + if (rc.right < 0) rc.right = 0; + if (rc.left > s_target_width) rc.left = s_target_width; + if (rc.right > s_target_width) rc.right = s_target_width; + if (rc.top < 0) rc.top = 0; + if (rc.bottom < 0) rc.bottom = 0; + if (rc.top > s_target_height) rc.top = s_target_height; + if (rc.bottom > s_target_height) rc.bottom = s_target_height; + + rc.left += Xstride; + rc.top += Ystride; + rc.right += Xstride; + rc.bottom += Ystride; + + if (rc.left > rc.right) + { + int temp = rc.right; + rc.right = rc.left; + rc.left = temp; + } + if (rc.top > rc.bottom) + { + int temp = rc.bottom; + rc.bottom = rc.top; + rc.top = temp; + } + + return (rc.right >= rc.left && rc.bottom >= rc.top); +} + +void RendererBase::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc) +{ + if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.bUseRealXFB) || !fbWidth || !fbHeight) + { + g_VideoInitialize.pCopiedToXFB(false); + return; + } + + // this function is called after the XFB field is changed, not after + // EFB is copied to XFB. In this way, flickering is reduced in games + // and seems to also give more FPS in ZTP + + if (field == FIELD_LOWER) + xfbAddr -= fbWidth * 2; + u32 xfbCount = 0; + const XFBSourceBase** xfbSourceList = g_framebuffer_manager->GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); + + if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + g_VideoInitialize.pCopiedToXFB(false); + return; + } + + g_renderer->ResetAPIState(); + + // prepare copying the XFBs to our backbuffer + TargetRectangle dst_rect; + ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); + + g_renderer->PrepareXFBCopy(dst_rect); + + if (g_ActiveConfig.bUseXFB) + { + const XFBSourceBase* xfbSource; + + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) + { + xfbSource = xfbSourceList[i]; + TargetRectangle sourceRc; + + //if (g_ActiveConfig.bAutoScale) + //{ + // sourceRc = xfbSource->sourceRc; + //} + //else + //{ + sourceRc.left = 0; + sourceRc.top = 0; + sourceRc.right = xfbSource->texWidth; + sourceRc.bottom = xfbSource->texHeight; + //} + + MathUtil::Rectangle drawRc; + + if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2); + + drawRc.bottom = 1.0f - 2.0f * ((hOffset) / (float)fbHeight); + drawRc.top = 1.0f - 2.0f * ((hOffset + xfbHeight) / (float)fbHeight); + drawRc.left = -(xfbWidth / (float)fbWidth); + drawRc.right = (xfbWidth / (float)fbWidth); + + if (!g_ActiveConfig.bAutoScale) + { + // scale draw area for a 1 to 1 pixel mapping with the draw target + float vScale = (float)fbHeight / (float)s_backbuffer_height; + float hScale = (float)fbWidth / (float)s_backbuffer_width; + + drawRc.top *= vScale; + drawRc.bottom *= vScale; + drawRc.left *= hScale; + drawRc.right *= hScale; + } + } + else + { + drawRc.top = -1; + drawRc.bottom = 1; + drawRc.left = -1; + drawRc.right = 1; + } + + g_renderer->Draw(xfbSource, sourceRc, drawRc, rc); + } + } + else + { + // TODO: organize drawRc stuff + MathUtil::Rectangle drawRc; + drawRc.top = -1; + drawRc.bottom = 1; + drawRc.left = -1; + drawRc.right = 1; + + const TargetRectangle targetRc = ConvertEFBRectangle(rc); + g_renderer->Draw(NULL, targetRc, drawRc, rc); + } + + // done with drawing the game stuff, good moment to save a screenshot + // TODO: screenshot code + // + + // finally present some information + // TODO: debug text, fps, etc... + // + + OSD::DrawMessages(); + + g_renderer->EndFrame(); + + ++frameCount; + + DLCache::ProgressiveCleanup(); + g_texture_cache->Cleanup(); + + // check for configuration changes + const int last_efbscale = g_ActiveConfig.iEFBScale; + //const int last_aa = g_ActiveConfig.iMultisampleMode; + + UpdateActiveConfig(); + + + bool window_resized = g_renderer->CheckForResize(); + + bool xfbchanged = false; + if (s_XFB_width != fbWidth || s_XFB_height != fbHeight) + { + xfbchanged = true; + s_XFB_width = fbWidth; + s_XFB_height = fbHeight; + if (s_XFB_width < 1) s_XFB_width = MAX_XFB_WIDTH; + if (s_XFB_width > MAX_XFB_WIDTH) s_XFB_width = MAX_XFB_WIDTH; + if (s_XFB_height < 1) s_XFB_height = MAX_XFB_HEIGHT; + if (s_XFB_height > MAX_XFB_HEIGHT) s_XFB_height = MAX_XFB_HEIGHT; + } + + // update FPS counter + // TODO: make this better + static int fpscount = 0; + static unsigned long lasttime = 0; + if (Common::Timer::GetTimeMs() - lasttime >= 1000) + { + lasttime = Common::Timer::GetTimeMs(); + s_fps = fpscount; + fpscount = 0; + } + if (XFBWrited) + ++fpscount; + + // set default viewport and scissor, for the clear to work correctly + stats.ResetFrame(); + + // done. Show our work ;) + g_renderer->Present(); + + // resize the back buffers NOW to avoid flickering when resizing windows + if (xfbchanged || window_resized || last_efbscale != g_ActiveConfig.iEFBScale) + { + g_renderer->GetBackBufferSize(&s_backbuffer_width, &s_backbuffer_height); + + FramebufferSize(s_backbuffer_width, s_backbuffer_height); + + g_renderer->RecreateFramebufferManger(); + } + + // begin next frame + g_renderer->RestoreAPIState(); + + g_renderer->BeginFrame(); + + g_renderer->UpdateViewport(); + VertexShaderManager::SetViewportChanged(); + g_VideoInitialize.pCopiedToXFB(XFBWrited || g_ActiveConfig.bUseRealXFB); + XFBWrited = false; +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/Renderer.h b/Source/Plugins/Plugin_VideoMerge/Src/Renderer.h index 980325d79d..a325b2b13e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/Renderer.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/Renderer.h @@ -1,99 +1,99 @@ - -#ifndef _RENDER_H_ -#define _RENDER_H_ - -#include "VideoCommon.h" -#include "CommonTypes.h" -#include "FramebufferManager.h" - -class RendererBase -{ -public: - RendererBase(); - virtual ~RendererBase() {} - - static void FramebufferSize(int w, int h); - - static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); - - virtual u32 AccessEFB(EFBAccessType type, int x, int y) = 0; - - static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc); - - // virtual funcs used in Swap() - virtual void PrepareXFBCopy(const TargetRectangle &dst_rect) = 0; - virtual void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, - const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) = 0; - virtual void EndFrame() = 0; - virtual void Present() = 0; - virtual bool CheckForResize() = 0; - virtual void GetBackBufferSize(int* w, int* h) = 0; - virtual void RecreateFramebufferManger() = 0; - virtual void BeginFrame() = 0; - - // hmm - virtual bool SetScissorRect() = 0; - static bool SetScissorRect(EFBRectangle &rc); - - static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc); - - virtual void UpdateViewport() = 0; - virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0; - - virtual void ResetAPIState() = 0; - virtual void RestoreAPIState() = 0; - - static int GetTargetWidth() { return s_target_width; } - static int GetTargetHeight() { return s_target_height; } - static int GetFullTargetWidth() { return s_Fulltarget_width; } - static int GetFullTargetHeight() { return s_Fulltarget_height; } - static float GetTargetScaleX() { return EFBxScale; } - static float GetTargetScaleY() { return EFByScale; } - static int GetFrameBufferWidth() { return s_backbuffer_width; } - static int GetFrameBufferHeight() { return s_backbuffer_height; } - static float GetXFBScaleX() { return xScale; } - static float GetXFBScaleY() { return yScale; } - - virtual void SetColorMask() {} - virtual void SetBlendMode(bool forceUpdate) {} - virtual void SetSamplerState(int stage, int texindex) {} - virtual void SetDitherMode() {} - virtual void SetLineWidth() {} - virtual void SetInterlacingMode() {} - virtual void SetGenerationMode() = 0; - virtual void SetDepthMode() = 0; - virtual void SetLogicOpMode() = 0; - -protected: - - // TODO: are all of these needed? - static int s_target_width; - static int s_target_height; - - static int s_Fulltarget_width; - static int s_Fulltarget_height; - - static int s_backbuffer_width; - static int s_backbuffer_height; - // - - static int s_fps; - - static u32 s_blendMode; - static bool XFBWrited; - - // these go with the settings in the GUI 1x,2x,3x,etc - static float EFBxScale; - static float EFByScale; - // these seem be the fractional value - // TODO: are these ones needed? - static float xScale; - static float yScale; - - static int s_XFB_width; - static int s_XFB_height; - - static volatile u32 s_swapRequested; -}; - -#endif + +#ifndef _RENDER_H_ +#define _RENDER_H_ + +#include "VideoCommon.h" +#include "CommonTypes.h" +#include "FramebufferManager.h" + +class RendererBase +{ +public: + RendererBase(); + virtual ~RendererBase() {} + + static void FramebufferSize(int w, int h); + + static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + + virtual u32 AccessEFB(EFBAccessType type, int x, int y) = 0; + + static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,const EFBRectangle& rc); + + // virtual funcs used in Swap() + virtual void PrepareXFBCopy(const TargetRectangle &dst_rect) = 0; + virtual void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc, + const MathUtil::Rectangle& drawRc, const EFBRectangle& rc) = 0; + virtual void EndFrame() = 0; + virtual void Present() = 0; + virtual bool CheckForResize() = 0; + virtual void GetBackBufferSize(int* w, int* h) = 0; + virtual void RecreateFramebufferManger() = 0; + virtual void BeginFrame() = 0; + + // hmm + virtual bool SetScissorRect() = 0; + static bool SetScissorRect(EFBRectangle &rc); + + static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc); + + virtual void UpdateViewport() = 0; + virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0; + + virtual void ResetAPIState() = 0; + virtual void RestoreAPIState() = 0; + + static int GetTargetWidth() { return s_target_width; } + static int GetTargetHeight() { return s_target_height; } + static int GetFullTargetWidth() { return s_Fulltarget_width; } + static int GetFullTargetHeight() { return s_Fulltarget_height; } + static float GetTargetScaleX() { return EFBxScale; } + static float GetTargetScaleY() { return EFByScale; } + static int GetFrameBufferWidth() { return s_backbuffer_width; } + static int GetFrameBufferHeight() { return s_backbuffer_height; } + static float GetXFBScaleX() { return xScale; } + static float GetXFBScaleY() { return yScale; } + + virtual void SetColorMask() {} + virtual void SetBlendMode(bool forceUpdate) {} + virtual void SetSamplerState(int stage, int texindex) {} + virtual void SetDitherMode() {} + virtual void SetLineWidth() {} + virtual void SetInterlacingMode() {} + virtual void SetGenerationMode() = 0; + virtual void SetDepthMode() = 0; + virtual void SetLogicOpMode() = 0; + +protected: + + // TODO: are all of these needed? + static int s_target_width; + static int s_target_height; + + static int s_Fulltarget_width; + static int s_Fulltarget_height; + + static int s_backbuffer_width; + static int s_backbuffer_height; + // + + static int s_fps; + + static u32 s_blendMode; + static bool XFBWrited; + + // these go with the settings in the GUI 1x,2x,3x,etc + static float EFBxScale; + static float EFByScale; + // these seem be the fractional value + // TODO: are these ones needed? + static float xScale; + static float yScale; + + static int s_XFB_width; + static int s_XFB_height; + + static volatile u32 s_swapRequested; +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.cpp index df2bc6fb5a..7304abbb90 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.cpp @@ -1,525 +1,525 @@ - -// Common -#include "MemoryUtil.h" - -#include "TextureCache.h" - -#include "VideoConfig.h" -#include "TextureDecoder.h" -#include "HiresTextures.h" - -#include "Statistics.h" - -#include "Main.h" - -TextureCacheBase::TexCache TextureCacheBase::textures; -u8 *TextureCacheBase::temp; - -enum -{ - TEMP_SIZE = (1024 * 1024 * 4), - TEXTURE_KILL_THRESHOLD = 200, -}; - -// returns the exponent of the smallest power of two which is greater than val -unsigned int GetPow2(unsigned int val) -{ - unsigned int ret = 0; - for (; val; val >>= 1) - ++ret; - return ret; -} - -TextureCacheBase::TCacheEntryBase::~TCacheEntryBase() -{ - // TODO: can we just use (addr) and remove the other checks? - // will need changes to TextureCache::Load and CopyRenderTargetToTexture - if (addr && false == (isRenderTarget || g_ActiveConfig.bSafeTextureCache)) - { - u32* ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr); - if (ptr && *ptr == hash) - *ptr = oldpixel; - } -} - -bool TextureCacheBase::TCacheEntryBase::IntersectsMemoryRange(u32 range_address, u32 range_size) const -{ - if (addr + size_in_bytes < range_address) - return false; - - if (addr >= range_address + range_size) - return false; - - return true; -} - -TextureCacheBase::TextureCacheBase() -{ - temp = (u8*)AllocateMemoryPages(TEMP_SIZE); - TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); - HiresTextures::Init(g_globals->unique_id); -} - -void TextureCacheBase::Cleanup() -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - while (iter != tcend) - { - if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) - { - delete iter->second; - textures.erase(iter++); - } - else - ++iter; - } -} - -TextureCacheBase::~TextureCacheBase() -{ - Invalidate(true); - FreeMemoryPages(temp, TEMP_SIZE); - temp = NULL; -} - -void TextureCacheBase::ClearRenderTargets() -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - for (; iter!=tcend; ++iter) - iter->second->isRenderTarget = false; -} - -void TextureCacheBase::MakeRangeDynamic(u32 start_address, u32 size) -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - for (; iter!=tcend; ++iter) - { - // TODO: an int ?? - int rangePosition = iter->second->IntersectsMemoryRange(start_address, size); - if (0 == rangePosition) - iter->second->hash = 0; - } -} - -void TextureCacheBase::Invalidate(bool shutdown) -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - for (; iter!=tcend; ++iter) - { - // TODO: this could be better - if (shutdown) - iter->second->addr = 0; // hax, not even helpin - delete iter->second; - } - - textures.clear(); - HiresTextures::Shutdown(); -} - -void TextureCacheBase::InvalidateRange(u32 start_address, u32 size) -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - while (iter != tcend) - { - if (iter->second->IntersectsMemoryRange(start_address, size)) - { - delete iter->second; - textures.erase(iter++); - } - else - ++iter; - } -} - -TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(unsigned int stage, - u32 address, unsigned int width, unsigned int height, unsigned int tex_format, - unsigned int tlutaddr, unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel) -{ - // necessary? - if (0 == address) - return NULL; - - u8* ptr = g_VideoInitialize.pGetMemoryPointer(address); - - // TexelSizeInNibbles(format)*width*height/16; - const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; - const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; - - unsigned int expandedWidth = (width + bsw) & (~bsw); - unsigned int expandedHeight = (height + bsh) & (~bsh); - - u64 hash_value = 0; - u64 texHash = 0; - u32 texID = address; - u32 FullFormat = tex_format; - u32 size_in_bytes = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format); - - switch (tex_format) - { - case GX_TF_C4: - case GX_TF_C8: - case GX_TF_C14X2: - FullFormat = tex_format | (tlutfmt << 16); - break; - - default: - break; - } - - // hires textures and texture dumping not supported, yet - if (g_ActiveConfig.bSafeTextureCache/* || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures*/) - { - texHash = GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - - switch (tex_format) - { - case GX_TF_C4: - case GX_TF_C8: - case GX_TF_C14X2: - { - // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up) - // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower. - // This trick (to change the texID depending on the TLUT addr) is a trick to get around - // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of - // each other stored in a single texture, and uses the palette to make different characters - // visible or invisible. Thus, unless we want to recreate the textures for every drawn character, - // we must make sure that texture with different tluts get different IDs. - const u64 tlutHash = GetHash64(texMem + tlutaddr, TexDecoder_GetPaletteSize(tex_format), - g_ActiveConfig.iSafeTextureCache_ColorSamples); - - texHash ^= tlutHash; - - if (g_ActiveConfig.bSafeTextureCache) - texID ^= ((u32)tlutHash) ^ (tlutHash >> 32); - } - break; - - default: - break; - } - - if (g_ActiveConfig.bSafeTextureCache) - hash_value = texHash; - } - - bool skip_texture_create = false; - - TCacheEntryBase *entry = textures[texID]; - if (entry) - { - if (!g_ActiveConfig.bSafeTextureCache) - hash_value = *(u32*)ptr; - - // TODO: Is the (entry->MipLevels == maxlevel) check needed? - if (entry->isRenderTarget || - (address == entry->addr && hash_value == entry->hash && - FullFormat == entry->fmt && entry->MipLevels == maxlevel)) - { - goto return_entry; - } - else - { - // Let's reload the new texture data into the same texture, - // instead of destroying it and having to create a new one. - // Might speed up movie playback very, very slightly. - - // TODO: Is the (entry->MipLevels < maxlevel) check needed? - if (width == entry->w && height==entry->h && - FullFormat == entry->fmt && entry->MipLevels < maxlevel) - { - goto load_texture; - } - else - { - delete entry; - } - } - } - - // create the texture - - const bool isPow2 = !((width & (width - 1)) || (height & (height - 1))); - unsigned int TexLevels = (isPow2 && UseNativeMips && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2; - - // TODO: what is ((maxlevel + 1) && maxlevel) ? - if (TexLevels > (maxlevel + 1) && maxlevel) - TexLevels = maxlevel + 1; - - const PC_TexFormat pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, - expandedHeight, tex_format, tlutaddr, tlutfmt, true); - - textures[texID] = entry = CreateTexture(width, height, expandedWidth, TexLevels, pcfmt); - - entry->oldpixel = *(u32*)ptr; - entry->addr = address; - entry->w = width; - entry->h = height; - entry->fmt = FullFormat; - entry->MipLevels = maxlevel; - entry->size_in_bytes = size_in_bytes; - - entry->isRenderTarget = false; - entry->isNonPow2 = false; - - if (g_ActiveConfig.bSafeTextureCache) - entry->hash = hash_value; - else - // WTF is this rand() doing here? - entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF); - -load_texture: - - entry->Load(width, height, expandedWidth, 0); - - if (TexLevels > 1 && pcfmt != PC_TEX_FMT_NONE) - { - const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format); - - unsigned int level = 1; - unsigned int mipWidth = (width + 1) >> 1; - unsigned int mipHeight = (height + 1) >> 1; - ptr += entry->size_in_bytes; - - while ((mipHeight || mipWidth) && (level < TexLevels)) - { - const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1; - const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; - - expandedWidth = (currentWidth + bsw) & (~bsw); - expandedHeight = (currentHeight + bsh) & (~bsh); - - TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true); - //entry->Load(currentWidth, currentHeight, expandedWidth, level); - - ptr += ((max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1); - mipWidth >>= 1; - mipHeight >>= 1; - ++level; - } - } - - INCSTAT(stats.numTexturesCreated); - SETSTAT(stats.numTexturesAlive, (int)textures.size()); - -return_entry: - - entry->frameCount = frameCount; - entry->Bind(stage); - - return entry; -} - -void TextureCacheBase::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, - bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect) -{ - float colmat[20] = {}; - // last four floats for fConstAdd - float *const fConstAdd = colmat + 16; - unsigned int cbufid = -1; - - // TODO: Move this to TextureCache::Init() - if (bFromZBuffer) - { - switch (copyfmt) - { - case 0: // Z4 - case 1: // Z8 - colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f; - cbufid = 12; - break; - - case 3: // Z16 //? - colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f; - cbufid = 13; - break; - - case 11: // Z16 (reverse order) - colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; - cbufid = 14; - break; - - case 6: // Z24X8 - colmat[0] = colmat[5] = colmat[10] = 1.0f; - cbufid = 15; - break; - - case 9: // Z8M - colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; - cbufid = 16; - break; - - case 10: // Z8L - colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; - cbufid = 17; - break; - - case 12: // Z16L - colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f; - cbufid = 18; - break; - - default: - ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt); - colmat[2] = colmat[5] = colmat[8] = 1.0f; - cbufid = 19; - break; - } - } - else if (bIsIntensityFmt) - { - fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f/255.0f; - switch (copyfmt) - { - case 0: // I4 - case 1: // I8 - case 2: // IA4 - case 3: // IA8 - // TODO - verify these coefficients - colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f; - colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f; - colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f; - - if (copyfmt < 2) - { - fConstAdd[3] = 16.0f / 255.0f; - colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f; - cbufid = 0; - } - else// alpha - { - colmat[15] = 1; - cbufid = 1; - } - - break; - - default: - ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt); - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; - break; - } - } - else - { - switch (copyfmt) - { - case 0: // R4 - case 8: // R8 - colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; - cbufid = 2; - break; - - case 2: // RA4 - case 3: // RA8 - colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1; - cbufid = 3; - break; - - case 7: // A8 - colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1; - cbufid = 4; - break; - - case 9: // G8 - colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1; - cbufid = 5; - break; - - case 10: // B8 - colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1; - cbufid = 6; - break; - - case 11: // RG8 - colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1; - cbufid = 7; - break; - - case 12: // GB8 - colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1; - cbufid = 8; - break; - - case 4: // RGB565 - colmat[0] = colmat[5] = colmat[10] = 1; - fConstAdd[3] = 1; // set alpha to 1 - cbufid = 9; - break; - - case 5: // RGB5A3 - case 6: // RGBA8 - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; - cbufid = 10; - break; - - default: - ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt); - colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; - cbufid = 11; - break; - } - } - - const int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf); - const int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf); - - const int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_w * g_renderer->GetTargetScaleX()) : tex_w; - const int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_h * g_renderer->GetTargetScaleY()) : tex_h; - - TCacheEntryBase* entry = NULL; - - const TexCache::iterator iter = textures.find(address); - if (textures.end() != iter) - { - entry = iter->second; - - if (entry->isRenderTarget && entry->Scaledw == scaled_tex_w && entry->Scaledh == scaled_tex_h) - { - goto load_texture; - } - else - { - // remove it and recreate it as a render target - delete entry; - textures.erase(iter); - } - } - - // create the texture - textures[address] = entry = CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h); - - if (NULL == entry) - PanicAlert("CopyRenderTargetToTexture failed to create entry.texture at %s %d\n", __FILE__, __LINE__); - - entry->addr = 0; // TODO: probably can use this and eliminate isRenderTarget - entry->hash = 0; - entry->w = tex_w; - entry->h = tex_h; - entry->Scaledw = scaled_tex_w; - entry->Scaledh = scaled_tex_h; - entry->fmt = copyfmt; - - entry->isRenderTarget = true; - entry->isNonPow2 = true; // TODO: is this used anywhere? - -load_texture: - - entry->frameCount = frameCount; - - g_renderer->ResetAPIState(); // reset any game specific settings - - // load the texture - entry->FromRenderTarget(bFromZBuffer, bScaleByHalf, cbufid, colmat, source_rect); - - g_renderer->RestoreAPIState(); -} + +// Common +#include "MemoryUtil.h" + +#include "TextureCache.h" + +#include "VideoConfig.h" +#include "TextureDecoder.h" +#include "HiresTextures.h" + +#include "Statistics.h" + +#include "Main.h" + +TextureCacheBase::TexCache TextureCacheBase::textures; +u8 *TextureCacheBase::temp; + +enum +{ + TEMP_SIZE = (1024 * 1024 * 4), + TEXTURE_KILL_THRESHOLD = 200, +}; + +// returns the exponent of the smallest power of two which is greater than val +unsigned int GetPow2(unsigned int val) +{ + unsigned int ret = 0; + for (; val; val >>= 1) + ++ret; + return ret; +} + +TextureCacheBase::TCacheEntryBase::~TCacheEntryBase() +{ + // TODO: can we just use (addr) and remove the other checks? + // will need changes to TextureCache::Load and CopyRenderTargetToTexture + if (addr && false == (isRenderTarget || g_ActiveConfig.bSafeTextureCache)) + { + u32* ptr = (u32*)g_VideoInitialize.pGetMemoryPointer(addr); + if (ptr && *ptr == hash) + *ptr = oldpixel; + } +} + +bool TextureCacheBase::TCacheEntryBase::IntersectsMemoryRange(u32 range_address, u32 range_size) const +{ + if (addr + size_in_bytes < range_address) + return false; + + if (addr >= range_address + range_size) + return false; + + return true; +} + +TextureCacheBase::TextureCacheBase() +{ + temp = (u8*)AllocateMemoryPages(TEMP_SIZE); + TexDecoder_SetTexFmtOverlayOptions(g_ActiveConfig.bTexFmtOverlayEnable, g_ActiveConfig.bTexFmtOverlayCenter); + HiresTextures::Init(g_globals->unique_id); +} + +void TextureCacheBase::Cleanup() +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + while (iter != tcend) + { + if (frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount) + { + delete iter->second; + textures.erase(iter++); + } + else + ++iter; + } +} + +TextureCacheBase::~TextureCacheBase() +{ + Invalidate(true); + FreeMemoryPages(temp, TEMP_SIZE); + temp = NULL; +} + +void TextureCacheBase::ClearRenderTargets() +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + for (; iter!=tcend; ++iter) + iter->second->isRenderTarget = false; +} + +void TextureCacheBase::MakeRangeDynamic(u32 start_address, u32 size) +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + for (; iter!=tcend; ++iter) + { + // TODO: an int ?? + int rangePosition = iter->second->IntersectsMemoryRange(start_address, size); + if (0 == rangePosition) + iter->second->hash = 0; + } +} + +void TextureCacheBase::Invalidate(bool shutdown) +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + for (; iter!=tcend; ++iter) + { + // TODO: this could be better + if (shutdown) + iter->second->addr = 0; // hax, not even helpin + delete iter->second; + } + + textures.clear(); + HiresTextures::Shutdown(); +} + +void TextureCacheBase::InvalidateRange(u32 start_address, u32 size) +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + while (iter != tcend) + { + if (iter->second->IntersectsMemoryRange(start_address, size)) + { + delete iter->second; + textures.erase(iter++); + } + else + ++iter; + } +} + +TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(unsigned int stage, + u32 address, unsigned int width, unsigned int height, unsigned int tex_format, + unsigned int tlutaddr, unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel) +{ + // necessary? + if (0 == address) + return NULL; + + u8* ptr = g_VideoInitialize.pGetMemoryPointer(address); + + // TexelSizeInNibbles(format)*width*height/16; + const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(tex_format) - 1; + const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(tex_format) - 1; + + unsigned int expandedWidth = (width + bsw) & (~bsw); + unsigned int expandedHeight = (height + bsh) & (~bsh); + + u64 hash_value = 0; + u64 texHash = 0; + u32 texID = address; + u32 FullFormat = tex_format; + u32 size_in_bytes = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format); + + switch (tex_format) + { + case GX_TF_C4: + case GX_TF_C8: + case GX_TF_C14X2: + FullFormat = tex_format | (tlutfmt << 16); + break; + + default: + break; + } + + // hires textures and texture dumping not supported, yet + if (g_ActiveConfig.bSafeTextureCache/* || g_ActiveConfig.bHiresTextures || g_ActiveConfig.bDumpTextures*/) + { + texHash = GetHash64(ptr, size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + + switch (tex_format) + { + case GX_TF_C4: + case GX_TF_C8: + case GX_TF_C14X2: + { + // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up) + // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower. + // This trick (to change the texID depending on the TLUT addr) is a trick to get around + // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of + // each other stored in a single texture, and uses the palette to make different characters + // visible or invisible. Thus, unless we want to recreate the textures for every drawn character, + // we must make sure that texture with different tluts get different IDs. + const u64 tlutHash = GetHash64(texMem + tlutaddr, TexDecoder_GetPaletteSize(tex_format), + g_ActiveConfig.iSafeTextureCache_ColorSamples); + + texHash ^= tlutHash; + + if (g_ActiveConfig.bSafeTextureCache) + texID ^= ((u32)tlutHash) ^ (tlutHash >> 32); + } + break; + + default: + break; + } + + if (g_ActiveConfig.bSafeTextureCache) + hash_value = texHash; + } + + bool skip_texture_create = false; + + TCacheEntryBase *entry = textures[texID]; + if (entry) + { + if (!g_ActiveConfig.bSafeTextureCache) + hash_value = *(u32*)ptr; + + // TODO: Is the (entry->MipLevels == maxlevel) check needed? + if (entry->isRenderTarget || + (address == entry->addr && hash_value == entry->hash && + FullFormat == entry->fmt && entry->MipLevels == maxlevel)) + { + goto return_entry; + } + else + { + // Let's reload the new texture data into the same texture, + // instead of destroying it and having to create a new one. + // Might speed up movie playback very, very slightly. + + // TODO: Is the (entry->MipLevels < maxlevel) check needed? + if (width == entry->w && height==entry->h && + FullFormat == entry->fmt && entry->MipLevels < maxlevel) + { + goto load_texture; + } + else + { + delete entry; + } + } + } + + // create the texture + + const bool isPow2 = !((width & (width - 1)) || (height & (height - 1))); + unsigned int TexLevels = (isPow2 && UseNativeMips && maxlevel) ? GetPow2(std::max(width, height)) : !isPow2; + + // TODO: what is ((maxlevel + 1) && maxlevel) ? + if (TexLevels > (maxlevel + 1) && maxlevel) + TexLevels = maxlevel + 1; + + const PC_TexFormat pcfmt = TexDecoder_Decode(temp, ptr, expandedWidth, + expandedHeight, tex_format, tlutaddr, tlutfmt, true); + + textures[texID] = entry = CreateTexture(width, height, expandedWidth, TexLevels, pcfmt); + + entry->oldpixel = *(u32*)ptr; + entry->addr = address; + entry->w = width; + entry->h = height; + entry->fmt = FullFormat; + entry->MipLevels = maxlevel; + entry->size_in_bytes = size_in_bytes; + + entry->isRenderTarget = false; + entry->isNonPow2 = false; + + if (g_ActiveConfig.bSafeTextureCache) + entry->hash = hash_value; + else + // WTF is this rand() doing here? + entry->hash = *(u32*)ptr = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF); + +load_texture: + + entry->Load(width, height, expandedWidth, 0); + + if (TexLevels > 1 && pcfmt != PC_TEX_FMT_NONE) + { + const unsigned int bsdepth = TexDecoder_GetTexelSizeInNibbles(tex_format); + + unsigned int level = 1; + unsigned int mipWidth = (width + 1) >> 1; + unsigned int mipHeight = (height + 1) >> 1; + ptr += entry->size_in_bytes; + + while ((mipHeight || mipWidth) && (level < TexLevels)) + { + const unsigned int currentWidth = (mipWidth > 0) ? mipWidth : 1; + const unsigned int currentHeight = (mipHeight > 0) ? mipHeight : 1; + + expandedWidth = (currentWidth + bsw) & (~bsw); + expandedHeight = (currentHeight + bsh) & (~bsh); + + TexDecoder_Decode(temp, ptr, expandedWidth, expandedHeight, tex_format, tlutaddr, tlutfmt, true); + //entry->Load(currentWidth, currentHeight, expandedWidth, level); + + ptr += ((max(mipWidth, bsw) * max(mipHeight, bsh) * bsdepth) >> 1); + mipWidth >>= 1; + mipHeight >>= 1; + ++level; + } + } + + INCSTAT(stats.numTexturesCreated); + SETSTAT(stats.numTexturesAlive, (int)textures.size()); + +return_entry: + + entry->frameCount = frameCount; + entry->Bind(stage); + + return entry; +} + +void TextureCacheBase::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, + bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect) +{ + float colmat[20] = {}; + // last four floats for fConstAdd + float *const fConstAdd = colmat + 16; + unsigned int cbufid = -1; + + // TODO: Move this to TextureCache::Init() + if (bFromZBuffer) + { + switch (copyfmt) + { + case 0: // Z4 + case 1: // Z8 + colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f; + cbufid = 12; + break; + + case 3: // Z16 //? + colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f; + cbufid = 13; + break; + + case 11: // Z16 (reverse order) + colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f; + cbufid = 14; + break; + + case 6: // Z24X8 + colmat[0] = colmat[5] = colmat[10] = 1.0f; + cbufid = 15; + break; + + case 9: // Z8M + colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f; + cbufid = 16; + break; + + case 10: // Z8L + colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f; + cbufid = 17; + break; + + case 12: // Z16L + colmat[2] = colmat[6] = colmat[10] = colmat[13] = 1.0f; + cbufid = 18; + break; + + default: + ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", copyfmt); + colmat[2] = colmat[5] = colmat[8] = 1.0f; + cbufid = 19; + break; + } + } + else if (bIsIntensityFmt) + { + fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f/255.0f; + switch (copyfmt) + { + case 0: // I4 + case 1: // I8 + case 2: // IA4 + case 3: // IA8 + // TODO - verify these coefficients + colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f; + colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f; + colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f; + + if (copyfmt < 2) + { + fConstAdd[3] = 16.0f / 255.0f; + colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f; + cbufid = 0; + } + else// alpha + { + colmat[15] = 1; + cbufid = 1; + } + + break; + + default: + ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", copyfmt); + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; + break; + } + } + else + { + switch (copyfmt) + { + case 0: // R4 + case 8: // R8 + colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1; + cbufid = 2; + break; + + case 2: // RA4 + case 3: // RA8 + colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1; + cbufid = 3; + break; + + case 7: // A8 + colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1; + cbufid = 4; + break; + + case 9: // G8 + colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1; + cbufid = 5; + break; + + case 10: // B8 + colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1; + cbufid = 6; + break; + + case 11: // RG8 + colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1; + cbufid = 7; + break; + + case 12: // GB8 + colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1; + cbufid = 8; + break; + + case 4: // RGB565 + colmat[0] = colmat[5] = colmat[10] = 1; + fConstAdd[3] = 1; // set alpha to 1 + cbufid = 9; + break; + + case 5: // RGB5A3 + case 6: // RGBA8 + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; + cbufid = 10; + break; + + default: + ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", copyfmt); + colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1; + cbufid = 11; + break; + } + } + + const int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf); + const int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf); + + const int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_w * g_renderer->GetTargetScaleX()) : tex_w; + const int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? (int)(tex_h * g_renderer->GetTargetScaleY()) : tex_h; + + TCacheEntryBase* entry = NULL; + + const TexCache::iterator iter = textures.find(address); + if (textures.end() != iter) + { + entry = iter->second; + + if (entry->isRenderTarget && entry->Scaledw == scaled_tex_w && entry->Scaledh == scaled_tex_h) + { + goto load_texture; + } + else + { + // remove it and recreate it as a render target + delete entry; + textures.erase(iter); + } + } + + // create the texture + textures[address] = entry = CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h); + + if (NULL == entry) + PanicAlert("CopyRenderTargetToTexture failed to create entry.texture at %s %d\n", __FILE__, __LINE__); + + entry->addr = 0; // TODO: probably can use this and eliminate isRenderTarget + entry->hash = 0; + entry->w = tex_w; + entry->h = tex_h; + entry->Scaledw = scaled_tex_w; + entry->Scaledh = scaled_tex_h; + entry->fmt = copyfmt; + + entry->isRenderTarget = true; + entry->isNonPow2 = true; // TODO: is this used anywhere? + +load_texture: + + entry->frameCount = frameCount; + + g_renderer->ResetAPIState(); // reset any game specific settings + + // load the texture + entry->FromRenderTarget(bFromZBuffer, bScaleByHalf, cbufid, colmat, source_rect); + + g_renderer->RestoreAPIState(); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.h b/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.h index 49c25dbc4a..193dad9c2b 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/TextureCache.h @@ -1,80 +1,80 @@ - -#ifndef _TEXTURECACHE_H_ -#define _TEXTURECACHE_H_ - -#include - -#include "CommonTypes.h" -#include "VideoCommon.h" -#include "TextureDecoder.h" - -unsigned int GetPow2(unsigned int val); - -class TextureCacheBase -{ -public: - struct TCacheEntryBase - { - u32 addr; - u32 size_in_bytes; - u64 hash; - u32 paletteHash; - u32 oldpixel; - - int frameCount; - unsigned int w, h, fmt, MipLevels; - int Scaledw, Scaledh; - - bool isRenderTarget; - bool isNonPow2; - - TCacheEntryBase() : addr(0), size_in_bytes(0), hash(0), paletteHash(0), oldpixel(0), - frameCount(0), w(0), h(0), fmt(0), MipLevels(0), Scaledw(0), Scaledh(0), - isRenderTarget(false), isNonPow2(true) {} - - virtual ~TCacheEntryBase(); - - virtual void Load(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int levels) = 0; - - virtual void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, - unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) = 0; - - virtual void Bind(unsigned int stage) = 0; - - bool IntersectsMemoryRange(u32 range_address, u32 range_size) const; - }; - - friend struct TCacheEntryBase; - - TextureCacheBase(); - virtual ~TextureCacheBase(); - - static void Cleanup(); - - static void Invalidate(bool shutdown); - static void InvalidateRange(u32 start_address, u32 size); - - // TODO: make these 2 static? - TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, - unsigned int height, unsigned int tex_format, unsigned int tlutaddr, - unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel); - - void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, - u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect); - - virtual TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, - unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0; - - virtual TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) = 0; - - static void ClearRenderTargets(); - static void MakeRangeDynamic(u32 start_address, u32 size); - -protected: - typedef std::map TexCache; - static TexCache textures; - static u8 *temp; -}; - -#endif + +#ifndef _TEXTURECACHE_H_ +#define _TEXTURECACHE_H_ + +#include + +#include "CommonTypes.h" +#include "VideoCommon.h" +#include "TextureDecoder.h" + +unsigned int GetPow2(unsigned int val); + +class TextureCacheBase +{ +public: + struct TCacheEntryBase + { + u32 addr; + u32 size_in_bytes; + u64 hash; + u32 paletteHash; + u32 oldpixel; + + int frameCount; + unsigned int w, h, fmt, MipLevels; + int Scaledw, Scaledh; + + bool isRenderTarget; + bool isNonPow2; + + TCacheEntryBase() : addr(0), size_in_bytes(0), hash(0), paletteHash(0), oldpixel(0), + frameCount(0), w(0), h(0), fmt(0), MipLevels(0), Scaledw(0), Scaledh(0), + isRenderTarget(false), isNonPow2(true) {} + + virtual ~TCacheEntryBase(); + + virtual void Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int levels) = 0; + + virtual void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf, + unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect) = 0; + + virtual void Bind(unsigned int stage) = 0; + + bool IntersectsMemoryRange(u32 range_address, u32 range_size) const; + }; + + friend struct TCacheEntryBase; + + TextureCacheBase(); + virtual ~TextureCacheBase(); + + static void Cleanup(); + + static void Invalidate(bool shutdown); + static void InvalidateRange(u32 start_address, u32 size); + + // TODO: make these 2 static? + TCacheEntryBase* Load(unsigned int stage, u32 address, unsigned int width, + unsigned int height, unsigned int tex_format, unsigned int tlutaddr, + unsigned int tlutfmt, bool UseNativeMips, unsigned int maxlevel); + + void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, + u32 copyfmt, bool bScaleByHalf, const EFBRectangle &source_rect); + + virtual TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt) = 0; + + virtual TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h) = 0; + + static void ClearRenderTargets(); + static void MakeRangeDynamic(u32 start_address, u32 size); + +protected: + typedef std::map TexCache; + static TexCache textures; + static u8 *temp; +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.cpp index 8a01541130..771243fb09 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.cpp @@ -1,268 +1,268 @@ - -// VideoCommon - -#include "CommonTypes.h" - -#include "OpcodeDecoding.h" -#include "IndexGenerator.h" -#include "Statistics.h" -#include "VideoConfig.h" -#include "PixelShaderManager.h" -#include "NativeVertexFormat.h" -#include "VertexShaderManager.h" -#include "Profiler.h" - -// -#include "TextureCache.h" -#include "VertexManager.h" -#include "Main.h" - -u16* VertexManagerBase::TIBuffer; -u16* VertexManagerBase::LIBuffer; -u16* VertexManagerBase::PIBuffer; -bool VertexManagerBase::Flushed; - -int VertexManagerBase::lastPrimitive; -u8* VertexManagerBase::LocalVBuffer; - -// TODO: put this in .h perhaps -extern NativeVertexFormat* g_nativeVertexFmt; - -NativeVertexFormat* NativeVertexFormat::Create() -{ - return g_vertex_manager->CreateNativeVertexFormat(); -} - -void VertexManagerBase::ResetBuffer() -{ - s_pCurBufferPointer = LocalVBuffer; -} - -VertexManagerBase::VertexManagerBase() -{ - LocalVBuffer = new u8[MAXVBUFFERSIZE]; - TIBuffer = new u16[MAXIBUFFERSIZE]; - LIBuffer = new u16[MAXIBUFFERSIZE]; - PIBuffer = new u16[MAXIBUFFERSIZE]; - - s_pCurBufferPointer = LocalVBuffer; - s_pBaseBufferPointer = LocalVBuffer; - - Flushed = false; - - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); -} - -VertexManagerBase::~VertexManagerBase() -{ - delete[] LocalVBuffer; - delete[] TIBuffer; - delete[] LIBuffer; - delete[] PIBuffer; - - // most likely not needed - ResetBuffer(); -} - -void VertexManagerBase::AddIndices(int _primitive, int _numVertices) -{ - switch (_primitive) - { - case GX_DRAW_QUADS: - IndexGenerator::AddQuads(_numVertices); - break; - - case GX_DRAW_TRIANGLES: - IndexGenerator::AddList(_numVertices); - break; - - case GX_DRAW_TRIANGLE_STRIP: - IndexGenerator::AddStrip(_numVertices); - break; - - case GX_DRAW_TRIANGLE_FAN: - IndexGenerator::AddFan(_numVertices); - break; - - case GX_DRAW_LINE_STRIP: - IndexGenerator::AddLineStrip(_numVertices); - break; - - case GX_DRAW_LINES: - IndexGenerator::AddLineList(_numVertices); - break; - - case GX_DRAW_POINTS: - IndexGenerator::AddPoints(_numVertices); - break; - } -} - -int VertexManager::GetRemainingSize() -{ - return VertexManagerBase::GetRemainingSize(); -} - -int VertexManagerBase::GetRemainingSize() -{ - return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer); - return 0; -} - -int VertexManagerBase::GetRemainingVertices(int primitive) -{ - switch (primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_TRIANGLES: - case GX_DRAW_TRIANGLE_STRIP: - case GX_DRAW_TRIANGLE_FAN: - return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3; - break; - - case GX_DRAW_LINE_STRIP: - case GX_DRAW_LINES: - return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2; - break; - - case GX_DRAW_POINTS: - return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen()); - break; - - default: - return 0; - break; - } -} - -void VertexManager::AddVertices(int _primitive, int _numVertices) -{ - VertexManagerBase::AddVertices(_primitive, _numVertices); -} - -void VertexManagerBase::AddVertices(int _primitive, int _numVertices) -{ - if (_numVertices <= 0) - return; - - switch (_primitive) - { - case GX_DRAW_QUADS: - case GX_DRAW_TRIANGLES: - case GX_DRAW_TRIANGLE_STRIP: - case GX_DRAW_TRIANGLE_FAN: - if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * _numVertices) - g_vertex_manager->Flush(); - break; - - case GX_DRAW_LINE_STRIP: - case GX_DRAW_LINES: - if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * _numVertices) - g_vertex_manager->Flush(); - break; - - case GX_DRAW_POINTS: - if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < _numVertices) - g_vertex_manager->Flush(); - break; - - default: - return; - break; - } - - if (Flushed) - { - IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); - Flushed = false; - } - - lastPrimitive = _primitive; - ADDSTAT(stats.thisFrame.numPrims, _numVertices); - INCSTAT(stats.thisFrame.numPrimitiveJoins); - AddIndices(_primitive, _numVertices); -} - -void VertexManager::Flush() -{ - VertexManagerBase::Flush(); -} - -void VertexManagerBase::Flush() -{ - if (LocalVBuffer == s_pCurBufferPointer) - return; - - if (Flushed) - return; - - Flushed = true; - - VideoFifo_CheckEFBAccess(); - - DVSTARTPROFILE(); - - u32 usedtextures = 0; - for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i) - { - if (bpmem.tevorders[i/2].getEnable(i & 1)) - usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1); - } - - if (bpmem.genMode.numindstages > 0) - for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1; ++i) - if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) - usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt); - - for (unsigned int i = 0; i < 8; ++i) - { - if (usedtextures & (1 << i)) - { - g_renderer->SetSamplerState(i & 3, i >> 2); - - FourTexUnits &tex = bpmem.tex[i >> 2]; - - TextureCacheBase::TCacheEntryBase* tentry = g_texture_cache->Load(i, - (tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5, - tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, - tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, - tex.texTlut[i&3].tlut_format, - (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips, - (tex.texMode1[i&3].max_lod >> 4)); - - if (tentry) - PixelShaderManager::SetTexDims(i, tentry->w, tentry->h, 0, 0); - else - ERROR_LOG(VIDEO, "error loading texture"); - } - } - - VertexShaderManager::SetConstants(); - PixelShaderManager::SetConstants(); - - if (false == g_pixel_shader_cache->SetShader(false)) - goto shader_fail; - - if (false == g_vertex_shader_cache->SetShader(g_nativeVertexFmt->m_components)) - goto shader_fail; - - const unsigned int stride = g_nativeVertexFmt->GetVertexStride(); - g_nativeVertexFmt->SetupVertexPointers(); - - // TODO: - g_vertex_manager->Draw(stride, false); - - if (false == g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate) - { - if (false == g_pixel_shader_cache->SetShader(true)) - goto shader_fail; - - // update alpha only - g_vertex_manager->Draw(stride, true); - } - - //IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); - -shader_fail: - ResetBuffer(); -} + +// VideoCommon + +#include "CommonTypes.h" + +#include "OpcodeDecoding.h" +#include "IndexGenerator.h" +#include "Statistics.h" +#include "VideoConfig.h" +#include "PixelShaderManager.h" +#include "NativeVertexFormat.h" +#include "VertexShaderManager.h" +#include "Profiler.h" + +// +#include "TextureCache.h" +#include "VertexManager.h" +#include "Main.h" + +u16* VertexManagerBase::TIBuffer; +u16* VertexManagerBase::LIBuffer; +u16* VertexManagerBase::PIBuffer; +bool VertexManagerBase::Flushed; + +int VertexManagerBase::lastPrimitive; +u8* VertexManagerBase::LocalVBuffer; + +// TODO: put this in .h perhaps +extern NativeVertexFormat* g_nativeVertexFmt; + +NativeVertexFormat* NativeVertexFormat::Create() +{ + return g_vertex_manager->CreateNativeVertexFormat(); +} + +void VertexManagerBase::ResetBuffer() +{ + s_pCurBufferPointer = LocalVBuffer; +} + +VertexManagerBase::VertexManagerBase() +{ + LocalVBuffer = new u8[MAXVBUFFERSIZE]; + TIBuffer = new u16[MAXIBUFFERSIZE]; + LIBuffer = new u16[MAXIBUFFERSIZE]; + PIBuffer = new u16[MAXIBUFFERSIZE]; + + s_pCurBufferPointer = LocalVBuffer; + s_pBaseBufferPointer = LocalVBuffer; + + Flushed = false; + + IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); +} + +VertexManagerBase::~VertexManagerBase() +{ + delete[] LocalVBuffer; + delete[] TIBuffer; + delete[] LIBuffer; + delete[] PIBuffer; + + // most likely not needed + ResetBuffer(); +} + +void VertexManagerBase::AddIndices(int _primitive, int _numVertices) +{ + switch (_primitive) + { + case GX_DRAW_QUADS: + IndexGenerator::AddQuads(_numVertices); + break; + + case GX_DRAW_TRIANGLES: + IndexGenerator::AddList(_numVertices); + break; + + case GX_DRAW_TRIANGLE_STRIP: + IndexGenerator::AddStrip(_numVertices); + break; + + case GX_DRAW_TRIANGLE_FAN: + IndexGenerator::AddFan(_numVertices); + break; + + case GX_DRAW_LINE_STRIP: + IndexGenerator::AddLineStrip(_numVertices); + break; + + case GX_DRAW_LINES: + IndexGenerator::AddLineList(_numVertices); + break; + + case GX_DRAW_POINTS: + IndexGenerator::AddPoints(_numVertices); + break; + } +} + +int VertexManager::GetRemainingSize() +{ + return VertexManagerBase::GetRemainingSize(); +} + +int VertexManagerBase::GetRemainingSize() +{ + return MAXVBUFFERSIZE - (int)(s_pCurBufferPointer - LocalVBuffer); + return 0; +} + +int VertexManagerBase::GetRemainingVertices(int primitive) +{ + switch (primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_TRIANGLES: + case GX_DRAW_TRIANGLE_STRIP: + case GX_DRAW_TRIANGLE_FAN: + return (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen()) / 3; + break; + + case GX_DRAW_LINE_STRIP: + case GX_DRAW_LINES: + return (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen()) / 2; + break; + + case GX_DRAW_POINTS: + return (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen()); + break; + + default: + return 0; + break; + } +} + +void VertexManager::AddVertices(int _primitive, int _numVertices) +{ + VertexManagerBase::AddVertices(_primitive, _numVertices); +} + +void VertexManagerBase::AddVertices(int _primitive, int _numVertices) +{ + if (_numVertices <= 0) + return; + + switch (_primitive) + { + case GX_DRAW_QUADS: + case GX_DRAW_TRIANGLES: + case GX_DRAW_TRIANGLE_STRIP: + case GX_DRAW_TRIANGLE_FAN: + if (MAXIBUFFERSIZE - IndexGenerator::GetTriangleindexLen() < 3 * _numVertices) + g_vertex_manager->Flush(); + break; + + case GX_DRAW_LINE_STRIP: + case GX_DRAW_LINES: + if (MAXIBUFFERSIZE - IndexGenerator::GetLineindexLen() < 2 * _numVertices) + g_vertex_manager->Flush(); + break; + + case GX_DRAW_POINTS: + if (MAXIBUFFERSIZE - IndexGenerator::GetPointindexLen() < _numVertices) + g_vertex_manager->Flush(); + break; + + default: + return; + break; + } + + if (Flushed) + { + IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); + Flushed = false; + } + + lastPrimitive = _primitive; + ADDSTAT(stats.thisFrame.numPrims, _numVertices); + INCSTAT(stats.thisFrame.numPrimitiveJoins); + AddIndices(_primitive, _numVertices); +} + +void VertexManager::Flush() +{ + VertexManagerBase::Flush(); +} + +void VertexManagerBase::Flush() +{ + if (LocalVBuffer == s_pCurBufferPointer) + return; + + if (Flushed) + return; + + Flushed = true; + + VideoFifo_CheckEFBAccess(); + + DVSTARTPROFILE(); + + u32 usedtextures = 0; + for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i) + { + if (bpmem.tevorders[i/2].getEnable(i & 1)) + usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1); + } + + if (bpmem.genMode.numindstages > 0) + for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1; ++i) + if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) + usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt); + + for (unsigned int i = 0; i < 8; ++i) + { + if (usedtextures & (1 << i)) + { + g_renderer->SetSamplerState(i & 3, i >> 2); + + FourTexUnits &tex = bpmem.tex[i >> 2]; + + TextureCacheBase::TCacheEntryBase* tentry = g_texture_cache->Load(i, + (tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5, + tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1, + tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9, + tex.texTlut[i&3].tlut_format, + (tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8) && g_ActiveConfig.bUseNativeMips, + (tex.texMode1[i&3].max_lod >> 4)); + + if (tentry) + PixelShaderManager::SetTexDims(i, tentry->w, tentry->h, 0, 0); + else + ERROR_LOG(VIDEO, "error loading texture"); + } + } + + VertexShaderManager::SetConstants(); + PixelShaderManager::SetConstants(); + + if (false == g_pixel_shader_cache->SetShader(false)) + goto shader_fail; + + if (false == g_vertex_shader_cache->SetShader(g_nativeVertexFmt->m_components)) + goto shader_fail; + + const unsigned int stride = g_nativeVertexFmt->GetVertexStride(); + g_nativeVertexFmt->SetupVertexPointers(); + + // TODO: + g_vertex_manager->Draw(stride, false); + + if (false == g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate) + { + if (false == g_pixel_shader_cache->SetShader(true)) + goto shader_fail; + + // update alpha only + g_vertex_manager->Draw(stride, true); + } + + //IndexGenerator::Start(TIBuffer, LIBuffer, PIBuffer); + +shader_fail: + ResetBuffer(); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.h b/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.h index a445d5f8ab..d62d8c933e 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/VertexManager.h @@ -1,47 +1,47 @@ - -#ifndef _VERTExMANAGER_H_ -#define _VERTExMANAGER_H_ - -#include "NativeVertexFormat.h" -#include "NativeVertexWriter.h" -#include "BPMemory.h" - -enum -{ - MAXVBUFFERSIZE = 0x50000, - MAXIBUFFERSIZE = 0x10000, -}; - -using VertexManager::s_pBaseBufferPointer; -using VertexManager::s_pCurBufferPointer; - -extern NativeVertexFormat *g_nativeVertexFmt; - -class VertexManagerBase -{ -public: - VertexManagerBase(); - virtual ~VertexManagerBase(); - - static void Flush(); - virtual void Draw(u32 stride, bool alphapass) = 0; - - virtual NativeVertexFormat* CreateNativeVertexFormat() = 0; - - static void AddIndices(int _primitive, int _numVertices); - static int GetRemainingSize(); - static int GetRemainingVertices(int primitive); - static void AddVertices(int _primitive, int _numVertices); - static void ResetBuffer(); - -protected: - static u16* TIBuffer; - static u16* LIBuffer; - static u16* PIBuffer; - static bool Flushed; - - static int lastPrimitive; - static u8* LocalVBuffer; -}; - -#endif + +#ifndef _VERTExMANAGER_H_ +#define _VERTExMANAGER_H_ + +#include "NativeVertexFormat.h" +#include "NativeVertexWriter.h" +#include "BPMemory.h" + +enum +{ + MAXVBUFFERSIZE = 0x50000, + MAXIBUFFERSIZE = 0x10000, +}; + +using VertexManager::s_pBaseBufferPointer; +using VertexManager::s_pCurBufferPointer; + +extern NativeVertexFormat *g_nativeVertexFmt; + +class VertexManagerBase +{ +public: + VertexManagerBase(); + virtual ~VertexManagerBase(); + + static void Flush(); + virtual void Draw(u32 stride, bool alphapass) = 0; + + virtual NativeVertexFormat* CreateNativeVertexFormat() = 0; + + static void AddIndices(int _primitive, int _numVertices); + static int GetRemainingSize(); + static int GetRemainingVertices(int primitive); + static void AddVertices(int _primitive, int _numVertices); + static void ResetBuffer(); + +protected: + static u16* TIBuffer; + static u16* LIBuffer; + static u16* PIBuffer; + static bool Flushed; + + static int lastPrimitive; + static u8* LocalVBuffer; +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.cpp index 6ac455e514..fceed482bb 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.cpp @@ -1,25 +1,25 @@ - -#include "VertexShaderManager.h" - -#include "Main.h" -#include "VertexShaderCache.h" - -void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) -{ - g_vertex_shader_cache->SetVSConstant4f(const_number, f1, f2, f3, f4); -} - -void SetVSConstant4fv(unsigned int const_number, const float* f) -{ - g_vertex_shader_cache->SetVSConstant4fv(const_number, f); -} - -void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) -{ - g_vertex_shader_cache->SetMultiVSConstant3fv(const_number, count, f); -} - -void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) -{ - g_vertex_shader_cache->SetMultiVSConstant4fv(const_number, count, f); -} + +#include "VertexShaderManager.h" + +#include "Main.h" +#include "VertexShaderCache.h" + +void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) +{ + g_vertex_shader_cache->SetVSConstant4f(const_number, f1, f2, f3, f4); +} + +void SetVSConstant4fv(unsigned int const_number, const float* f) +{ + g_vertex_shader_cache->SetVSConstant4fv(const_number, f); +} + +void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) +{ + g_vertex_shader_cache->SetMultiVSConstant3fv(const_number, count, f); +} + +void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) +{ + g_vertex_shader_cache->SetMultiVSConstant4fv(const_number, count, f); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.h b/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.h index c8b47cd644..dc7b640185 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/VertexShaderCache.h @@ -1,18 +1,18 @@ - -#ifndef _VERTEXSHADERCACHE_H_ -#define _VERTEXSHADERCACHE_H_ - -class VertexShaderCacheBase -{ -public: - virtual ~VertexShaderCacheBase() {} - - virtual bool SetShader(u32 components) = 0; - - virtual void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0; - virtual void SetVSConstant4fv(unsigned int const_number, const float* f) = 0; - virtual void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) = 0; - virtual void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) = 0; -}; - -#endif + +#ifndef _VERTEXSHADERCACHE_H_ +#define _VERTEXSHADERCACHE_H_ + +class VertexShaderCacheBase +{ +public: + virtual ~VertexShaderCacheBase() {} + + virtual bool SetShader(u32 components) = 0; + + virtual void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4) = 0; + virtual void SetVSConstant4fv(unsigned int const_number, const float* f) = 0; + virtual void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f) = 0; + virtual void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f) = 0; +}; + +#endif diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.cpp b/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.cpp index 5ef26c896f..c42cf36841 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.cpp +++ b/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.cpp @@ -1,245 +1,245 @@ - -#include "VideoConfigDiag.h" - -#include "VideoConfig.h" -#include "Main.h" - -#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s) - -// template instantiation -template class BoolSetting; -template class BoolSetting; - -typedef BoolSetting SettingCheckBox; -typedef BoolSetting SettingRadioButton; - -SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style) - : wxCheckBox(parent, -1, label, wxDefaultPosition, wxDefaultSize, style) - , m_setting(setting) - , m_reverse(reverse) -{ - SetValue(m_setting ^ m_reverse); - _connect_macro_(this, BoolSetting::UpdateValue, wxEVT_COMMAND_CHECKBOX_CLICKED, this); -} - -SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style) - : wxRadioButton(parent, -1, label, wxDefaultPosition, wxDefaultSize, style) - , m_setting(setting) - , m_reverse(reverse) -{ - SetValue(m_setting ^ m_reverse); - _connect_macro_(this, BoolSetting::UpdateValue, wxEVT_COMMAND_RADIOBUTTON_SELECTED, this); -} - -template -void BoolSetting::UpdateValue(wxCommandEvent& ev) -{ - m_setting = (ev.GetInt() != 0) ^ m_reverse; -} - -SettingChoice::SettingChoice(wxWindow* parent, int &setting, int num, const wxString choices[]) - : wxChoice(parent, -1, wxDefaultPosition, wxDefaultSize, num, choices) - , m_setting(setting) -{ - Select(m_setting); - _connect_macro_(this, SettingChoice::UpdateValue, wxEVT_COMMAND_CHOICE_SELECTED, this); -} - -void SettingChoice::UpdateValue(wxCommandEvent& ev) -{ - m_setting = ev.GetInt(); -} - -void VideoConfigDiag::CloseDiag(wxCommandEvent&) -{ - Close(); -} - -VideoConfigDiag::VideoConfigDiag(wxWindow* parent) - : wxDialog(parent, -1, wxT("Dolphin Graphics Configuration"), wxDefaultPosition, wxDefaultSize) -{ - VideoConfig &vconfig = g_Config; - - wxNotebook* const notebook = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize); - - // -- GENERAL -- - { - wxPanel* const page_general = new wxPanel(notebook, -1, wxDefaultPosition); - notebook->AddPage(page_general, wxT("General")); - wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); - - // - basic - { - wxStaticBoxSizer* const group_basic = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Basic")); - szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5); - wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5); - group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - // graphics api - { - const wxString gfxapi_choices[] = { wxT("Software [not present]"), - wxT("OpenGL [broken]"), wxT("Direct3D 9 [broken]"), wxT("Direct3D 11") }; - - szr_basic->Add(new wxStaticText(page_general, -1, wxT("Graphics API:")), 1, wxALIGN_CENTER_VERTICAL, 0); - wxChoice* const choice_gfxapi = new SettingChoice(page_general, - g_gfxapi, sizeof(gfxapi_choices)/sizeof(*gfxapi_choices), gfxapi_choices); - szr_basic->Add(choice_gfxapi, 1, 0, 0); - } - - // for D3D only - // adapter - { - //szr_basic->Add(new wxStaticText(page_general, -1, wxT("Adapter:")), 1, wxALIGN_CENTER_VERTICAL, 5); - //wxChoice* const choice_adapter = new SettingChoice(page_general, vconfig.iAdapter); - //szr_basic->Add(choice_adapter, 1, 0, 0); - } - - // aspect-ratio - { - const wxString ar_choices[] = { wxT("Auto [recommended]"), - wxT("Force 16:9"), wxT("Force 4:3"), wxT("Strech to Window") }; - - szr_basic->Add(new wxStaticText(page_general, -1, wxT("Aspect ratio:")), 1, wxALIGN_CENTER_VERTICAL, 0); - wxChoice* const choice_aspect = new SettingChoice(page_general, - vconfig.iAspectRatio, sizeof(ar_choices)/sizeof(*ar_choices), ar_choices); - szr_basic->Add(choice_aspect, 1, 0, 0); - } - - // widescreen hack - { - szr_basic->AddStretchSpacer(1); - szr_basic->Add(new SettingCheckBox(page_general, wxT("Widescreen Hack"), vconfig.bWidescreenHack), 1, 0, 0); - szr_basic->AddStretchSpacer(1); - szr_basic->Add(new SettingCheckBox(page_general, wxT("V-Sync"), vconfig.bVSync), 1, 0, 0); - } - - // - EFB - { - wxStaticBoxSizer* const group_efb = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("EFB")); - szr_general->Add(group_efb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - group_efb->Add(new SettingCheckBox(page_general, wxT("Enable CPU Access"), vconfig.bEFBAccessEnable), 0, wxBOTTOM | wxLEFT, 5); - - // EFB scale - { - // TODO: give this a label - const wxString efbscale_choices[] = { wxT("Fractional"), wxT("Integral [recommended]"), - wxT("1x"), wxT("2x"), wxT("3x")/*, wxT("4x")*/ }; - - wxChoice *const choice_efbscale = new SettingChoice(page_general, - vconfig.iEFBScale, sizeof(efbscale_choices)/sizeof(*efbscale_choices), efbscale_choices); - group_efb->Add(choice_efbscale, 0, wxBOTTOM | wxLEFT, 5); - } - - // EFB copy - wxStaticBoxSizer* const group_efbcopy = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Copy")); - group_efb->Add(group_efbcopy, 0, wxEXPAND | wxBOTTOM, 5); - - group_efbcopy->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bEFBCopyDisable, true), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); - group_efbcopy->AddStretchSpacer(1); - group_efbcopy->Add(new SettingRadioButton(page_general, wxT("Texture"), vconfig.bCopyEFBToTexture, false, wxRB_GROUP), 0, wxRIGHT, 5); - group_efbcopy->Add(new SettingRadioButton(page_general, wxT("RAM"), vconfig.bCopyEFBToTexture, true), 0, wxRIGHT, 5); - } - - // - safe texture cache - { - wxStaticBoxSizer* const group_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Safe Texture Cache")); - szr_general->Add(group_safetex, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - // safe texture cache - group_safetex->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bSafeTextureCache), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); - group_safetex->AddStretchSpacer(1); - // TODO: make these radio buttons functional - //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Safe"), - // wxDefaultPosition, wxDefaultSize, wxRB_GROUP), 0, wxRIGHT, 5); - //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Normal")), 0, wxRIGHT, 5); - //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Fast")), 0, wxRIGHT, 5); - } - - } - - page_general->SetSizerAndFit(szr_general); - } - - // -- ADVANCED -- - { - wxPanel* const page_advanced = new wxPanel(notebook, -1, wxDefaultPosition); - notebook->AddPage(page_advanced, wxT("Advanced")); - wxBoxSizer* const szr_advanced = new wxBoxSizer(wxVERTICAL); - - // - rendering - { - wxStaticBoxSizer* const group_rendering = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Rendering")); - szr_advanced->Add(group_rendering, 0, wxEXPAND | wxALL, 5); - wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5); - group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Enable Wireframe"), vconfig.bWireFrame)); - szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Lighting"), vconfig.bDisableLighting)); - szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Textures"), vconfig.bDisableTexturing)); - szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Fog"), vconfig.bDisableFog)); - szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Dest. Alpha Pass"), vconfig.bDstAlphaPass)); - } - - // - info - { - wxStaticBoxSizer* const group_info = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Overlay Information")); - szr_advanced->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5); - group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - szr_info->Add(new SettingCheckBox(page_advanced, wxT("Show FPS"), vconfig.bShowFPS)); - szr_info->Add(new SettingCheckBox(page_advanced, wxT("Various Statistics"), vconfig.bOverlayStats)); - szr_info->Add(new SettingCheckBox(page_advanced, wxT("Projection Stats"), vconfig.bOverlayProjStats)); - szr_info->Add(new SettingCheckBox(page_advanced, wxT("Texture Format"), vconfig.bTexFmtOverlayEnable)); - szr_info->Add(new SettingCheckBox(page_advanced, wxT("EFB Copy Regions"), vconfig.bShowEFBCopyRegions)); - } - - // - XFB - { - wxStaticBoxSizer* const group_xfb = new wxStaticBoxSizer(wxHORIZONTAL, page_advanced, wxT("XFB")); - szr_advanced->Add(group_xfb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - group_xfb->Add(new SettingCheckBox(page_advanced, wxT("Enable"), vconfig.bUseXFB), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); - group_xfb->AddStretchSpacer(1); - group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Virtual"), vconfig.bUseRealXFB, true, wxRB_GROUP), 0, wxRIGHT, 5); - group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Real"), vconfig.bUseRealXFB), 0, wxRIGHT, 5); - } - - // - utility - { - wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Utility")); - szr_advanced->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); - group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); - - szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Textures"), vconfig.bDumpTextures)); - szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Load Hi-Res Textures"), vconfig.bHiresTextures)); - szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump EFB Target"), vconfig.bDumpEFBTarget)); - szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Frames"), vconfig.bDumpFrames)); - szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Free Look"), vconfig.bFreeLook)); - } - - // stuff to move/remove - { - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Load Native Mipmaps"), vconfig.bUseNativeMips), 0, wxBOTTOM | wxLEFT, 5); - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("EFB Scaled Copy"), vconfig.bCopyEFBScaled), 0, wxBOTTOM | wxLEFT, 5); - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Auto Scale"), vconfig.bAutoScale), 0, wxBOTTOM | wxLEFT, 5); - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Crop"), vconfig.bCrop), 0, wxBOTTOM | wxLEFT, 5); - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable OpenCL"), vconfig.bEnableOpenCL), 0, wxBOTTOM | wxLEFT, 5); - szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable Display List Caching"), vconfig.bDlistCachingEnable), 0, wxBOTTOM | wxLEFT, 5); - } - - page_advanced->SetSizerAndFit(szr_advanced); - } - - wxButton* const btn_close = new wxButton(this, -1, wxT("Close"), wxDefaultPosition); - _connect_macro_(btn_close, VideoConfigDiag::CloseDiag, wxEVT_COMMAND_BUTTON_CLICKED, this); - - wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); - szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); - szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); - - SetSizerAndFit(szr_main); - Center(); -} + +#include "VideoConfigDiag.h" + +#include "VideoConfig.h" +#include "Main.h" + +#define _connect_macro_(b, f, c, s) (b)->Connect(wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s) + +// template instantiation +template class BoolSetting; +template class BoolSetting; + +typedef BoolSetting SettingCheckBox; +typedef BoolSetting SettingRadioButton; + +SettingCheckBox::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style) + : wxCheckBox(parent, -1, label, wxDefaultPosition, wxDefaultSize, style) + , m_setting(setting) + , m_reverse(reverse) +{ + SetValue(m_setting ^ m_reverse); + _connect_macro_(this, BoolSetting::UpdateValue, wxEVT_COMMAND_CHECKBOX_CLICKED, this); +} + +SettingRadioButton::BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse, long style) + : wxRadioButton(parent, -1, label, wxDefaultPosition, wxDefaultSize, style) + , m_setting(setting) + , m_reverse(reverse) +{ + SetValue(m_setting ^ m_reverse); + _connect_macro_(this, BoolSetting::UpdateValue, wxEVT_COMMAND_RADIOBUTTON_SELECTED, this); +} + +template +void BoolSetting::UpdateValue(wxCommandEvent& ev) +{ + m_setting = (ev.GetInt() != 0) ^ m_reverse; +} + +SettingChoice::SettingChoice(wxWindow* parent, int &setting, int num, const wxString choices[]) + : wxChoice(parent, -1, wxDefaultPosition, wxDefaultSize, num, choices) + , m_setting(setting) +{ + Select(m_setting); + _connect_macro_(this, SettingChoice::UpdateValue, wxEVT_COMMAND_CHOICE_SELECTED, this); +} + +void SettingChoice::UpdateValue(wxCommandEvent& ev) +{ + m_setting = ev.GetInt(); +} + +void VideoConfigDiag::CloseDiag(wxCommandEvent&) +{ + Close(); +} + +VideoConfigDiag::VideoConfigDiag(wxWindow* parent) + : wxDialog(parent, -1, wxT("Dolphin Graphics Configuration"), wxDefaultPosition, wxDefaultSize) +{ + VideoConfig &vconfig = g_Config; + + wxNotebook* const notebook = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize); + + // -- GENERAL -- + { + wxPanel* const page_general = new wxPanel(notebook, -1, wxDefaultPosition); + notebook->AddPage(page_general, wxT("General")); + wxBoxSizer* const szr_general = new wxBoxSizer(wxVERTICAL); + + // - basic + { + wxStaticBoxSizer* const group_basic = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("Basic")); + szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5); + wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5); + group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + // graphics api + { + const wxString gfxapi_choices[] = { wxT("Software [not present]"), + wxT("OpenGL [broken]"), wxT("Direct3D 9 [broken]"), wxT("Direct3D 11") }; + + szr_basic->Add(new wxStaticText(page_general, -1, wxT("Graphics API:")), 1, wxALIGN_CENTER_VERTICAL, 0); + wxChoice* const choice_gfxapi = new SettingChoice(page_general, + g_gfxapi, sizeof(gfxapi_choices)/sizeof(*gfxapi_choices), gfxapi_choices); + szr_basic->Add(choice_gfxapi, 1, 0, 0); + } + + // for D3D only + // adapter + { + //szr_basic->Add(new wxStaticText(page_general, -1, wxT("Adapter:")), 1, wxALIGN_CENTER_VERTICAL, 5); + //wxChoice* const choice_adapter = new SettingChoice(page_general, vconfig.iAdapter); + //szr_basic->Add(choice_adapter, 1, 0, 0); + } + + // aspect-ratio + { + const wxString ar_choices[] = { wxT("Auto [recommended]"), + wxT("Force 16:9"), wxT("Force 4:3"), wxT("Strech to Window") }; + + szr_basic->Add(new wxStaticText(page_general, -1, wxT("Aspect ratio:")), 1, wxALIGN_CENTER_VERTICAL, 0); + wxChoice* const choice_aspect = new SettingChoice(page_general, + vconfig.iAspectRatio, sizeof(ar_choices)/sizeof(*ar_choices), ar_choices); + szr_basic->Add(choice_aspect, 1, 0, 0); + } + + // widescreen hack + { + szr_basic->AddStretchSpacer(1); + szr_basic->Add(new SettingCheckBox(page_general, wxT("Widescreen Hack"), vconfig.bWidescreenHack), 1, 0, 0); + szr_basic->AddStretchSpacer(1); + szr_basic->Add(new SettingCheckBox(page_general, wxT("V-Sync"), vconfig.bVSync), 1, 0, 0); + } + + // - EFB + { + wxStaticBoxSizer* const group_efb = new wxStaticBoxSizer(wxVERTICAL, page_general, wxT("EFB")); + szr_general->Add(group_efb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + group_efb->Add(new SettingCheckBox(page_general, wxT("Enable CPU Access"), vconfig.bEFBAccessEnable), 0, wxBOTTOM | wxLEFT, 5); + + // EFB scale + { + // TODO: give this a label + const wxString efbscale_choices[] = { wxT("Fractional"), wxT("Integral [recommended]"), + wxT("1x"), wxT("2x"), wxT("3x")/*, wxT("4x")*/ }; + + wxChoice *const choice_efbscale = new SettingChoice(page_general, + vconfig.iEFBScale, sizeof(efbscale_choices)/sizeof(*efbscale_choices), efbscale_choices); + group_efb->Add(choice_efbscale, 0, wxBOTTOM | wxLEFT, 5); + } + + // EFB copy + wxStaticBoxSizer* const group_efbcopy = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Copy")); + group_efb->Add(group_efbcopy, 0, wxEXPAND | wxBOTTOM, 5); + + group_efbcopy->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bEFBCopyDisable, true), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); + group_efbcopy->AddStretchSpacer(1); + group_efbcopy->Add(new SettingRadioButton(page_general, wxT("Texture"), vconfig.bCopyEFBToTexture, false, wxRB_GROUP), 0, wxRIGHT, 5); + group_efbcopy->Add(new SettingRadioButton(page_general, wxT("RAM"), vconfig.bCopyEFBToTexture, true), 0, wxRIGHT, 5); + } + + // - safe texture cache + { + wxStaticBoxSizer* const group_safetex = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Safe Texture Cache")); + szr_general->Add(group_safetex, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + // safe texture cache + group_safetex->Add(new SettingCheckBox(page_general, wxT("Enable"), vconfig.bSafeTextureCache), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); + group_safetex->AddStretchSpacer(1); + // TODO: make these radio buttons functional + //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Safe"), + // wxDefaultPosition, wxDefaultSize, wxRB_GROUP), 0, wxRIGHT, 5); + //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Normal")), 0, wxRIGHT, 5); + //group_safetex->Add(new wxRadioButton(page_general, -1, wxT("Fast")), 0, wxRIGHT, 5); + } + + } + + page_general->SetSizerAndFit(szr_general); + } + + // -- ADVANCED -- + { + wxPanel* const page_advanced = new wxPanel(notebook, -1, wxDefaultPosition); + notebook->AddPage(page_advanced, wxT("Advanced")); + wxBoxSizer* const szr_advanced = new wxBoxSizer(wxVERTICAL); + + // - rendering + { + wxStaticBoxSizer* const group_rendering = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Rendering")); + szr_advanced->Add(group_rendering, 0, wxEXPAND | wxALL, 5); + wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5); + group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Enable Wireframe"), vconfig.bWireFrame)); + szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Lighting"), vconfig.bDisableLighting)); + szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Textures"), vconfig.bDisableTexturing)); + szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Fog"), vconfig.bDisableFog)); + szr_rendering->Add(new SettingCheckBox(page_advanced, wxT("Disable Dest. Alpha Pass"), vconfig.bDstAlphaPass)); + } + + // - info + { + wxStaticBoxSizer* const group_info = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Overlay Information")); + szr_advanced->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5); + group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + szr_info->Add(new SettingCheckBox(page_advanced, wxT("Show FPS"), vconfig.bShowFPS)); + szr_info->Add(new SettingCheckBox(page_advanced, wxT("Various Statistics"), vconfig.bOverlayStats)); + szr_info->Add(new SettingCheckBox(page_advanced, wxT("Projection Stats"), vconfig.bOverlayProjStats)); + szr_info->Add(new SettingCheckBox(page_advanced, wxT("Texture Format"), vconfig.bTexFmtOverlayEnable)); + szr_info->Add(new SettingCheckBox(page_advanced, wxT("EFB Copy Regions"), vconfig.bShowEFBCopyRegions)); + } + + // - XFB + { + wxStaticBoxSizer* const group_xfb = new wxStaticBoxSizer(wxHORIZONTAL, page_advanced, wxT("XFB")); + szr_advanced->Add(group_xfb, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + group_xfb->Add(new SettingCheckBox(page_advanced, wxT("Enable"), vconfig.bUseXFB), 0, wxLEFT | wxRIGHT | wxBOTTOM, 5); + group_xfb->AddStretchSpacer(1); + group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Virtual"), vconfig.bUseRealXFB, true, wxRB_GROUP), 0, wxRIGHT, 5); + group_xfb->Add(new SettingRadioButton(page_advanced, wxT("Real"), vconfig.bUseRealXFB), 0, wxRIGHT, 5); + } + + // - utility + { + wxStaticBoxSizer* const group_utility = new wxStaticBoxSizer(wxVERTICAL, page_advanced, wxT("Utility")); + szr_advanced->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5); + group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); + + szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Textures"), vconfig.bDumpTextures)); + szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Load Hi-Res Textures"), vconfig.bHiresTextures)); + szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump EFB Target"), vconfig.bDumpEFBTarget)); + szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Dump Frames"), vconfig.bDumpFrames)); + szr_utility->Add(new SettingCheckBox(page_advanced, wxT("Free Look"), vconfig.bFreeLook)); + } + + // stuff to move/remove + { + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Load Native Mipmaps"), vconfig.bUseNativeMips), 0, wxBOTTOM | wxLEFT, 5); + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("EFB Scaled Copy"), vconfig.bCopyEFBScaled), 0, wxBOTTOM | wxLEFT, 5); + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Auto Scale"), vconfig.bAutoScale), 0, wxBOTTOM | wxLEFT, 5); + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Crop"), vconfig.bCrop), 0, wxBOTTOM | wxLEFT, 5); + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable OpenCL"), vconfig.bEnableOpenCL), 0, wxBOTTOM | wxLEFT, 5); + szr_advanced->Add(new SettingCheckBox(page_advanced, wxT("Enable Display List Caching"), vconfig.bDlistCachingEnable), 0, wxBOTTOM | wxLEFT, 5); + } + + page_advanced->SetSizerAndFit(szr_advanced); + } + + wxButton* const btn_close = new wxButton(this, -1, wxT("Close"), wxDefaultPosition); + _connect_macro_(btn_close, VideoConfigDiag::CloseDiag, wxEVT_COMMAND_BUTTON_CLICKED, this); + + wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL); + szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5); + szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5); + + SetSizerAndFit(szr_main); + Center(); +} diff --git a/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.h b/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.h index 327f71b663..d0997d3d5a 100644 --- a/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.h +++ b/Source/Plugins/Plugin_VideoMerge/Src/VideoConfigDiag.h @@ -1,44 +1,44 @@ - -#ifndef _CONFIG_DIAG_H_ -#define _CONFIG_DIAG_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -template -class BoolSetting : public W -{ -public: - BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse = false, long style = 0); - void UpdateValue(wxCommandEvent& ev); -private: - bool &m_setting; - const bool m_reverse; -}; - -class SettingChoice : public wxChoice -{ -public: - SettingChoice(wxWindow* parent, int &setting, int num = 0, const wxString choices[] = NULL); - void UpdateValue(wxCommandEvent& ev); -private: - int &m_setting; -}; - -class VideoConfigDiag : public wxDialog -{ -public: - VideoConfigDiag(wxWindow* parent); - -protected: - void CloseDiag(wxCommandEvent&); -}; - -#endif + +#ifndef _CONFIG_DIAG_H_ +#define _CONFIG_DIAG_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +class BoolSetting : public W +{ +public: + BoolSetting(wxWindow* parent, const wxString& label, bool &setting, bool reverse = false, long style = 0); + void UpdateValue(wxCommandEvent& ev); +private: + bool &m_setting; + const bool m_reverse; +}; + +class SettingChoice : public wxChoice +{ +public: + SettingChoice(wxWindow* parent, int &setting, int num = 0, const wxString choices[] = NULL); + void UpdateValue(wxCommandEvent& ev); +private: + int &m_setting; +}; + +class VideoConfigDiag : public wxDialog +{ +public: + VideoConfigDiag(wxWindow* parent); + +protected: + void CloseDiag(wxCommandEvent&); +}; + +#endif diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/SConscript b/Source/Plugins/Plugin_WiimoteNew/Src/SConscript index af62cff9da..108566f78a 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/SConscript +++ b/Source/Plugins/Plugin_WiimoteNew/Src/SConscript @@ -13,6 +13,7 @@ files = [ 'WiimoteEmu/Attachment/Nunchuk.cpp', 'WiimoteEmu/Attachment/Drums.cpp', 'WiimoteEmu/Attachment/Guitar.cpp', + 'WiimoteEmu/Attachment/Turntable.cpp', 'WiimoteEmu/EmuSubroutines.cpp', 'WiimoteEmu/Encryption.cpp', 'WiimoteEmu/Speaker.cpp', diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.cpp index e107ba6e83..5cb88aef0e 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.cpp @@ -1,122 +1,122 @@ -#include "Turntable.h" - - -namespace WiimoteEmu -{ - -static const u8 turntable_id[] = {0x03, 0x00, 0xa4, 0x20, 0x01, 0x03}; - -static const u16 turntable_button_bitmasks[] = -{ - Turntable::BUTTON_L_GREEN, - Turntable::BUTTON_L_RED, - Turntable::BUTTON_L_BLUE, - Turntable::BUTTON_R_GREEN, - Turntable::BUTTON_R_RED, - Turntable::BUTTON_R_BLUE, - Turntable::BUTTON_MINUS, - Turntable::BUTTON_PLUS, - Turntable::BUTTON_EUPHORIA, -}; - -static const char* const turntable_button_names[] = -{ - "Green Left", "Red Left", "Blue Left", - "Green Right", "Red Right", "Blue Right", - "-", "+", "Euphoria", -}; - -Turntable::Turntable() : Attachment("Turntable") -{ - // buttons - // TODO: separate buttons into Left and Right - groups.push_back(m_buttons = new Buttons("Buttons")); - for (unsigned int i = 0; i < sizeof(turntable_button_names)/sizeof(*turntable_button_names); ++i) - m_buttons->controls.push_back(new ControlGroup::Input( turntable_button_names[i])); - - // stick - groups.push_back(m_stick = new AnalogStick("Stick")); - - // TODO: - groups.push_back(m_effect_dial = new Triggers("Effect")); - m_effect_dial->controls.push_back(new ControlGroup::Input("Dial")); - - //m_left_turntable - //m_right_turntable - //m_crossfade_slider - - // set up register - // id - memcpy(®[0xfa], turntable_id, sizeof(turntable_id)); -} - -void Turntable::GetState(u8* const data, const bool focus) -{ - wm_turntable_extension* const ttdata = (wm_turntable_extension*)data; - ttdata->bt = 0; - - // stick - { - u8 x, y; - m_stick->GetState(&x, &y, 0x20, focus ? 0x1F /*0x15*/ : 0); - - ttdata->sx = x; - ttdata->sy = y; - } - - // left table - // TODO: - { - s8 tt = 0; - //m_left_turntable->GetState(&tt .....); - - ttdata->ltable1 = tt; - ttdata->ltable2 = tt << 5; - } - - // right table - // TODO: - { - s8 tt = 0; - //m_right_turntable->GetState(&tt .....); - - ttdata->rtable1 = tt; - ttdata->rtable2 = tt << 1; - ttdata->rtable3 = tt << 3; - ttdata->rtable4 = tt << 5; - } - - // effect dial - { - u8 dial = 0; - m_effect_dial->GetState(&dial, focus ? 0xF : 0); - - ttdata->dial1 = dial; - ttdata->dial2 = dial << 3; - } - - // crossfade slider - // TODO: - { - u8 cfs = 0; - //m_crossfade_slider->GetState(&cfs .....); - - ttdata->slider = cfs; - } - - if (focus) - { - // buttons - m_buttons->GetState(&ttdata->bt, turntable_button_bitmasks); - } - - // flip button bits :/ - ttdata->bt ^= ( - BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | - BUTTON_R_GREEN | BUTTON_R_RED | BUTTON_R_BLUE | - BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA - ); -} - - -} +#include "Turntable.h" + + +namespace WiimoteEmu +{ + +static const u8 turntable_id[] = {0x03, 0x00, 0xa4, 0x20, 0x01, 0x03}; + +static const u16 turntable_button_bitmasks[] = +{ + Turntable::BUTTON_L_GREEN, + Turntable::BUTTON_L_RED, + Turntable::BUTTON_L_BLUE, + Turntable::BUTTON_R_GREEN, + Turntable::BUTTON_R_RED, + Turntable::BUTTON_R_BLUE, + Turntable::BUTTON_MINUS, + Turntable::BUTTON_PLUS, + Turntable::BUTTON_EUPHORIA, +}; + +static const char* const turntable_button_names[] = +{ + "Green Left", "Red Left", "Blue Left", + "Green Right", "Red Right", "Blue Right", + "-", "+", "Euphoria", +}; + +Turntable::Turntable() : Attachment("Turntable") +{ + // buttons + // TODO: separate buttons into Left and Right + groups.push_back(m_buttons = new Buttons("Buttons")); + for (unsigned int i = 0; i < sizeof(turntable_button_names)/sizeof(*turntable_button_names); ++i) + m_buttons->controls.push_back(new ControlGroup::Input( turntable_button_names[i])); + + // stick + groups.push_back(m_stick = new AnalogStick("Stick")); + + // TODO: + groups.push_back(m_effect_dial = new Triggers("Effect")); + m_effect_dial->controls.push_back(new ControlGroup::Input("Dial")); + + //m_left_turntable + //m_right_turntable + //m_crossfade_slider + + // set up register + // id + memcpy(®[0xfa], turntable_id, sizeof(turntable_id)); +} + +void Turntable::GetState(u8* const data, const bool focus) +{ + wm_turntable_extension* const ttdata = (wm_turntable_extension*)data; + ttdata->bt = 0; + + // stick + { + u8 x, y; + m_stick->GetState(&x, &y, 0x20, focus ? 0x1F /*0x15*/ : 0); + + ttdata->sx = x; + ttdata->sy = y; + } + + // left table + // TODO: + { + s8 tt = 0; + //m_left_turntable->GetState(&tt .....); + + ttdata->ltable1 = tt; + ttdata->ltable2 = tt << 5; + } + + // right table + // TODO: + { + s8 tt = 0; + //m_right_turntable->GetState(&tt .....); + + ttdata->rtable1 = tt; + ttdata->rtable2 = tt << 1; + ttdata->rtable3 = tt << 3; + ttdata->rtable4 = tt << 5; + } + + // effect dial + { + u8 dial = 0; + m_effect_dial->GetState(&dial, focus ? 0xF : 0); + + ttdata->dial1 = dial; + ttdata->dial2 = dial << 3; + } + + // crossfade slider + // TODO: + { + u8 cfs = 0; + //m_crossfade_slider->GetState(&cfs .....); + + ttdata->slider = cfs; + } + + if (focus) + { + // buttons + m_buttons->GetState(&ttdata->bt, turntable_button_bitmasks); + } + + // flip button bits :/ + ttdata->bt ^= ( + BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | + BUTTON_R_GREEN | BUTTON_R_RED | BUTTON_R_BLUE | + BUTTON_MINUS | BUTTON_PLUS | BUTTON_EUPHORIA + ); +} + + +} diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.h b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.h index 5e2e4e9c16..6d0afe924f 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.h +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Turntable.h @@ -1,42 +1,42 @@ -#include "Attachment.h" - -namespace WiimoteEmu -{ - -class Turntable : public Attachment -{ -public: - Turntable(); - void GetState(u8* const data, const bool focus); - - enum - { - BUTTON_EUPHORIA = 0x1000, - - BUTTON_L_GREEN = 0x0800, - BUTTON_L_RED = 0x20, - BUTTON_L_BLUE = 0x8000, - - BUTTON_R_GREEN = 0x2000, - BUTTON_R_RED = 0x02, - BUTTON_R_BLUE = 0x0400, - - BUTTON_MINUS = 0x10, - BUTTON_PLUS = 0x04, - }; - -private: - Buttons* m_buttons; - MixedTriggers* m_triggers; - AnalogStick* m_stick; - - Triggers *m_effect_dial; - - // TODO: - //m_left_turntable - //m_right_turntable - //m_crossfade_slider -}; - - -} +#include "Attachment.h" + +namespace WiimoteEmu +{ + +class Turntable : public Attachment +{ +public: + Turntable(); + void GetState(u8* const data, const bool focus); + + enum + { + BUTTON_EUPHORIA = 0x1000, + + BUTTON_L_GREEN = 0x0800, + BUTTON_L_RED = 0x20, + BUTTON_L_BLUE = 0x8000, + + BUTTON_R_GREEN = 0x2000, + BUTTON_R_RED = 0x02, + BUTTON_R_BLUE = 0x0400, + + BUTTON_MINUS = 0x10, + BUTTON_PLUS = 0x04, + }; + +private: + Buttons* m_buttons; + MixedTriggers* m_triggers; + AnalogStick* m_stick; + + Triggers *m_effect_dial; + + // TODO: + //m_left_turntable + //m_right_turntable + //m_crossfade_slider +}; + + +} diff --git a/Source/TestSuite/ASM/ASM.vcproj b/Source/TestSuite/ASM/ASM.vcproj index b86117f527..b0cdfc10ed 100644 --- a/Source/TestSuite/ASM/ASM.vcproj +++ b/Source/TestSuite/ASM/ASM.vcproj @@ -1,95 +1,95 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +