Merge 'master' into shader-uids-awesome.

Conflicts:
	Source/Core/VideoCommon/Src/LightingShaderGen.cpp
	Source/Core/VideoCommon/Src/PixelShaderGen.cpp
	Source/Core/VideoCommon/Src/PixelShaderGen.h
	Source/Core/VideoCommon/Src/PixelShaderManager.cpp
	Source/Core/VideoCommon/Src/VertexShaderGen.cpp
	Source/Core/VideoCommon/Src/VertexShaderGen.h
	Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h
	Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp
	Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.h
This commit is contained in:
NeoBrainX
2013-03-26 22:21:19 +01:00
753 changed files with 99248 additions and 100494 deletions
@@ -199,6 +199,7 @@
<ClCompile Include="Src\LineGeometryShader.cpp" />
<ClCompile Include="Src\main.cpp" />
<ClCompile Include="Src\NativeVertexFormat.cpp" />
<ClCompile Include="Src\PerfQuery.cpp" />
<ClCompile Include="Src\PixelShaderCache.cpp" />
<ClCompile Include="Src\PointGeometryShader.cpp" />
<ClCompile Include="Src\PSTextureEncoder.cpp" />
@@ -228,6 +229,7 @@
<ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\LineGeometryShader.h" />
<ClInclude Include="Src\main.h" />
<ClInclude Include="Src\PerfQuery.h" />
<ClInclude Include="Src\PixelShaderCache.h" />
<ClInclude Include="Src\PointGeometryShader.h" />
<ClInclude Include="Src\PSTextureEncoder.h" />
@@ -57,6 +57,9 @@
<ClCompile Include="Src\PointGeometryShader.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PerfQuery.cpp">
<Filter>Render</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\Globals.h" />
@@ -117,6 +120,9 @@
<ClInclude Include="Src\PointGeometryShader.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PerfQuery.h">
<Filter>Render</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D">
@@ -520,7 +520,7 @@ void EndFrame()
void Present()
{
// TODO: Is 1 the correct value for vsyncing?
swapchain->Present((UINT)g_ActiveConfig.bVSync, 0);
swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0);
}
} // namespace D3D
@@ -64,7 +64,8 @@ bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
@@ -121,7 +122,8 @@ bool CompileGeometryShader(const char* code, unsigned int len, D3DBlob** blob,
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_gs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
@@ -180,7 +182,8 @@ bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob,
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
@@ -208,6 +208,8 @@ void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState(); // reset any game specific settings
// Copy EFB data to XFB and restore render target again
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
@@ -222,6 +224,8 @@ void XFBSource::CopyEFB(float Gamma)
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
}
} // namespace DX11
@@ -0,0 +1,150 @@
#include "RenderBase.h"
#include "D3DBase.h"
#include "PerfQuery.h"
namespace DX11 {
PerfQuery::PerfQuery()
: m_query_read_pos()
, m_query_count()
{
for (int i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
{
D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
D3D::device->CreateQuery(&qdesc, &m_query_buffer[i].query);
}
ResetQuery();
}
PerfQuery::~PerfQuery()
{
for (int i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
{
// TODO: EndQuery?
m_query_buffer[i].query->Release();
}
}
void PerfQuery::EnableQuery(PerfQueryGroup type)
{
// Is this sane?
if (m_query_count > ARRAYSIZE(m_query_buffer) / 2)
WeakFlush();
if (ARRAYSIZE(m_query_buffer) == m_query_count)
{
// TODO
FlushOne();
ERROR_LOG(VIDEO, "flushed query buffer early!");
}
// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ARRAYSIZE(m_query_buffer)];
D3D::context->Begin(entry.query);
entry.query_type = type;
++m_query_count;
}
}
void PerfQuery::DisableQuery(PerfQueryGroup type)
{
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + ARRAYSIZE(m_query_buffer)-1) % ARRAYSIZE(m_query_buffer)];
D3D::context->End(entry.query);
}
}
void PerfQuery::ResetQuery()
{
m_query_count = 0;
std::fill_n(m_results, ARRAYSIZE(m_results), 0);
}
u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
u32 result = 0;
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
{
result = m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
{
result = m_results[PQG_ZCOMP];
}
else if (type == PQ_BLEND_INPUT)
{
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_EFB_COPY_CLOCKS)
{
result = m_results[PQG_EFB_COPY_CLOCKS];
}
return result / 4;
}
void PerfQuery::FlushOne()
{
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = S_FALSE;
while (hr != S_OK)
{
// TODO: Might cause us to be stuck in an infinite loop!
hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0);
}
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
m_query_read_pos = (m_query_read_pos + 1) % ARRAYSIZE(m_query_buffer);
--m_query_count;
}
// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
{
while (!IsFlushed())
FlushOne();
}
void PerfQuery::WeakFlush()
{
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (hr == S_OK)
{
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
m_query_read_pos = (m_query_read_pos + 1) % ARRAYSIZE(m_query_buffer);
--m_query_count;
}
else
{
break;
}
}
}
bool PerfQuery::IsFlushed() const
{
return 0 == m_query_count;
}
} // namespace
@@ -0,0 +1,46 @@
#ifndef _PERFQUERY_H_
#define _PERFQUERY_H_
#include "PerfQueryBase.h"
namespace DX11 {
class PerfQuery : public PerfQueryBase
{
public:
PerfQuery();
~PerfQuery();
void EnableQuery(PerfQueryGroup type);
void DisableQuery(PerfQueryGroup type);
void ResetQuery();
u32 GetQueryResult(PerfQueryType type);
void FlushResults();
bool IsFlushed() const;
private:
struct ActiveQuery
{
ID3D11Query* query;
PerfQueryGroup query_type;
};
void WeakFlush();
// Only use when non-empty
void FlushOne();
// when testing in SMS: 64 was too small, 128 was ok
static const int PERF_QUERY_BUFFER_SIZE = 512;
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
int m_query_read_pos;
// TODO: sloppy
volatile int m_query_count;
volatile u32 m_results[PQG_NUM_MEMBERS];
};
} // namespace
#endif // _PERFQUERY_H_
+159 -171
View File
@@ -54,8 +54,6 @@ static int s_fps = 0;
static u32 s_LastAA = 0;
static u32 s_blendMode;
static Television s_television;
ID3D11Buffer* access_efb_cbuf = NULL;
@@ -67,6 +65,7 @@ ID3D11RasterizerState* resetraststate = NULL;
static ID3D11Texture2D* s_screenshot_texture = NULL;
// GX pipeline state
struct
{
@@ -76,151 +75,6 @@ struct
D3D11_RASTERIZER_DESC rastdc;
} gx_state;
// State translation lookup tables
static const D3D11_BLEND d3dSrcFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_DEST_COLOR,
D3D11_BLEND_INV_DEST_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
static const D3D11_BLEND d3dDestFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_SRC_COLOR,
D3D11_BLEND_INV_SRC_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
static const D3D11_BLEND_OP d3dLogicOps[16] =
{
D3D11_BLEND_OP_ADD,//0
D3D11_BLEND_OP_ADD,//1
D3D11_BLEND_OP_SUBTRACT,//2
D3D11_BLEND_OP_ADD,//3
D3D11_BLEND_OP_REV_SUBTRACT,//4
D3D11_BLEND_OP_ADD,//5
D3D11_BLEND_OP_MAX,//6
D3D11_BLEND_OP_ADD,//7
D3D11_BLEND_OP_MAX,//8
D3D11_BLEND_OP_MAX,//9
D3D11_BLEND_OP_ADD,//10
D3D11_BLEND_OP_ADD,//11
D3D11_BLEND_OP_ADD,//12
D3D11_BLEND_OP_ADD,//13
D3D11_BLEND_OP_ADD,//14
D3D11_BLEND_OP_ADD//15
};
static const D3D11_BLEND d3dLogicOpSrcFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_DEST_COLOR,//1
D3D11_BLEND_ONE,//2
D3D11_BLEND_ONE,//3
D3D11_BLEND_DEST_COLOR,//4
D3D11_BLEND_ZERO,//5
D3D11_BLEND_INV_DEST_COLOR,//6
D3D11_BLEND_INV_DEST_COLOR,//7
D3D11_BLEND_INV_SRC_COLOR,//8
D3D11_BLEND_INV_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_ONE,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_INV_SRC_COLOR,//13
D3D11_BLEND_INV_DEST_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_BLEND d3dLogicOpDestFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_ZERO,//1
D3D11_BLEND_INV_SRC_COLOR,//2
D3D11_BLEND_ZERO,//3
D3D11_BLEND_ONE,//4
D3D11_BLEND_ONE,//5
D3D11_BLEND_INV_SRC_COLOR,//6
D3D11_BLEND_ONE,//7
D3D11_BLEND_INV_DEST_COLOR,//8
D3D11_BLEND_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_INV_DEST_COLOR,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_ONE,//13
D3D11_BLEND_INV_SRC_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_CULL_MODE d3dCullModes[4] =
{
D3D11_CULL_NONE,
D3D11_CULL_BACK,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
};
static const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_ALWAYS
};
#define TEXF_NONE 0
#define TEXF_POINT 1
#define TEXF_LINEAR 2
static const unsigned int d3dMipFilters[4] =
{
TEXF_NONE,
TEXF_POINT,
TEXF_LINEAR,
TEXF_NONE, //reserved
};
static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
void SetupDeviceObjects()
{
@@ -338,7 +192,6 @@ void CreateScreenshotTexture()
Renderer::Renderer()
{
int x, y, w_temp, h_temp;
s_blendMode = 0;
InitFPSCounter();
@@ -833,6 +686,32 @@ void SetBlendOp(D3D11_BLEND_OP val)
void Renderer::SetBlendMode(bool forceUpdate)
{
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
const D3D11_BLEND d3dSrcFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_DEST_COLOR,
D3D11_BLEND_INV_DEST_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
(target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE,
(target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
const D3D11_BLEND d3dDestFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_SRC_COLOR,
D3D11_BLEND_INV_SRC_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled!
(target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE,
(target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO
};
if (bpmem.blendmode.logicopenable && !forceUpdate)
return;
@@ -845,8 +724,8 @@ void Renderer::SetBlendMode(bool forceUpdate)
}
else
{
gx_state.blenddc.RenderTarget[0].BlendEnable = bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0));
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)))
gx_state.blenddc.RenderTarget[0].BlendEnable = bpmem.blendmode.blendenable;
if (bpmem.blendmode.blendenable)
{
SetBlendOp(D3D11_BLEND_OP_ADD);
SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]);
@@ -883,11 +762,11 @@ bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle
return SUCCEEDED(hr);
}
void formatBufferDump(const char *in, char *out, int w, int h, int p)
void formatBufferDump(const u8* in, u8* out, int w, int h, int p)
{
for (int y = 0; y < h; ++y)
{
const u8 *line = (u8*)(in + (h - y - 1) * p);
auto line = (in + (h - y - 1) * p);
for (int x = 0; x < w; ++x)
{
out[0] = line[2];
@@ -904,8 +783,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{
if (g_ActiveConfig.bDumpFrames && frame_data)
AVIDump::AddFrame(frame_data);
if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false);
return;
@@ -916,8 +795,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
{
if (g_ActiveConfig.bDumpFrames && frame_data)
AVIDump::AddFrame(frame_data);
if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false);
return;
@@ -1056,16 +935,15 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map);
if (!frame_data || w != s_recordWidth || h != s_recordHeight)
if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight)
{
delete[] frame_data;
frame_data = new char[3 * s_recordWidth * s_recordHeight];
frame_data.resize(3 * s_recordWidth * s_recordHeight);
w = s_recordWidth;
h = s_recordHeight;
}
char* source_ptr = (char*)map.pData + GetTargetRectangle().left*4 + GetTargetRectangle().top*map.RowPitch;
formatBufferDump(source_ptr, frame_data, s_recordWidth, s_recordHeight, map.RowPitch);
AVIDump::AddFrame(frame_data);
auto source_ptr = (const u8*)map.pData + GetTargetRectangle().left*4 + GetTargetRectangle().top*map.RowPitch;
formatBufferDump(source_ptr, &frame_data[0], s_recordWidth, s_recordHeight, map.RowPitch);
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
D3D::context->Unmap(s_screenshot_texture, 0);
}
bLastFrameDumped = true;
@@ -1074,7 +952,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
if (bLastFrameDumped && bAVIDumping)
{
SAFE_DELETE_ARRAY(frame_data);
std::vector<u8>().swap(frame_data);
w = h = 0;
AVIDump::Stop();
@@ -1331,12 +1209,32 @@ void Renderer::RestoreCull()
void Renderer::SetGenerationMode()
{
const D3D11_CULL_MODE d3dCullModes[4] =
{
D3D11_CULL_NONE,
D3D11_CULL_BACK,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
};
// rastdc.FrontCounterClockwise must be false for this to work
gx_state.rastdc.CullMode = d3dCullModes[bpmem.genMode.cullmode];
}
void Renderer::SetDepthMode()
{
const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_ALWAYS
};
if (bpmem.zmode.testenable)
{
gx_state.depthdc.DepthEnable = TRUE;
@@ -1353,9 +1251,85 @@ void Renderer::SetDepthMode()
void Renderer::SetLogicOpMode()
{
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
// D3D11 doesn't support logic blending, so this is a huge hack
// TODO: Make use of D3D11.1's logic blending support
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
const D3D11_BLEND_OP d3dLogicOps[16] =
{
D3D11_BLEND_OP_ADD,//0
D3D11_BLEND_OP_ADD,//1
D3D11_BLEND_OP_SUBTRACT,//2
D3D11_BLEND_OP_ADD,//3
D3D11_BLEND_OP_REV_SUBTRACT,//4
D3D11_BLEND_OP_ADD,//5
D3D11_BLEND_OP_MAX,//6
D3D11_BLEND_OP_ADD,//7
D3D11_BLEND_OP_MAX,//8
D3D11_BLEND_OP_MAX,//9
D3D11_BLEND_OP_ADD,//10
D3D11_BLEND_OP_ADD,//11
D3D11_BLEND_OP_ADD,//12
D3D11_BLEND_OP_ADD,//13
D3D11_BLEND_OP_ADD,//14
D3D11_BLEND_OP_ADD//15
};
const D3D11_BLEND d3dLogicOpSrcFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_DEST_COLOR,//1
D3D11_BLEND_ONE,//2
D3D11_BLEND_ONE,//3
D3D11_BLEND_DEST_COLOR,//4
D3D11_BLEND_ZERO,//5
D3D11_BLEND_INV_DEST_COLOR,//6
D3D11_BLEND_INV_DEST_COLOR,//7
D3D11_BLEND_INV_SRC_COLOR,//8
D3D11_BLEND_INV_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_ONE,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_INV_SRC_COLOR,//13
D3D11_BLEND_INV_DEST_COLOR,//14
D3D11_BLEND_ONE//15
};
const D3D11_BLEND d3dLogicOpDestFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_ZERO,//1
D3D11_BLEND_INV_SRC_COLOR,//2
D3D11_BLEND_ZERO,//3
D3D11_BLEND_ONE,//4
D3D11_BLEND_ONE,//5
D3D11_BLEND_INV_SRC_COLOR,//6
D3D11_BLEND_ONE,//7
D3D11_BLEND_INV_DEST_COLOR,//8
D3D11_BLEND_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_INV_DEST_COLOR,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_ONE,//13
D3D11_BLEND_INV_SRC_COLOR,//14
D3D11_BLEND_ONE//15
};
if (bpmem.blendmode.logicopenable)
{
s_blendMode = 0;
gx_state.blenddc.RenderTarget[0].BlendEnable = true;
SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]);
SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]);
@@ -1379,18 +1353,32 @@ void Renderer::SetLineWidth()
void Renderer::SetSamplerState(int stage, int texindex)
{
#define TEXF_NONE 0
#define TEXF_POINT 1
#define TEXF_LINEAR 2
const unsigned int d3dMipFilters[4] =
{
TEXF_NONE,
TEXF_POINT,
TEXF_LINEAR,
TEXF_NONE, //reserved
};
const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
const FourTexUnits &tex = bpmem.tex[texindex];
const TexMode0 &tm0 = tex.texMode0[stage];
const TexMode1 &tm1 = tex.texMode1[stage];
unsigned int mip;
mip = (tm0.min_filter == 8) ? TEXF_NONE:d3dMipFilters[tm0.min_filter & 3];
if ((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) mip = TEXF_NONE;
unsigned int mip = d3dMipFilters[tm0.min_filter & 3];
if (texindex) stage += 4;
// TODO: Clarify whether these values are correct
// NOTE: since there's no "no filter" in DX11 we're using point filters in these cases
if (g_ActiveConfig.bForceFiltering)
{
gx_state.sampdc[stage].Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
@@ -1432,7 +1420,7 @@ void Renderer::SetSamplerState(int stage, int texindex)
// When mipfilter is set to "none", just disable mipmapping altogether
gx_state.sampdc[stage].MaxLOD = (mip == TEXF_NONE) ? 0.0f : (float)tm1.max_lod/16.f;
gx_state.sampdc[stage].MinLOD = (float)tm1.min_lod/16.f;
gx_state.sampdc[stage].MipLODBias = (float)tm0.lod_bias/32.0f;
gx_state.sampdc[stage].MipLODBias = (s32)tm0.lod_bias/32.0f;
}
void Renderer::SetInterlacingMode()
@@ -59,12 +59,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips)
unsigned int expanded_width, unsigned int level)
{
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
if (autogen_mips)
PD3DX11FilterTexture(D3D::context, texture->GetTex(), 0, D3DX11_DEFAULT);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
@@ -101,6 +98,9 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
SAFE_RELEASE(pTexture);
if (tex_levels != 1)
entry->Load(width, height, expanded_width, 0);
return entry;
}
@@ -41,7 +41,7 @@ private:
~TCacheEntry();
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false);
unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
@@ -39,41 +39,41 @@ namespace DX11
{
// TODO: Find sensible values for these two
const UINT IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * 16 * sizeof(u16);
const UINT VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE * 16;
const UINT MAXVBUFFER_COUNT = 2;
const UINT IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
const UINT VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
const UINT MAX_VBUFFER_COUNT = 2;
void VertexManager::CreateDeviceObjects()
{
D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(IBUFFER_SIZE,
D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
m_vertexDrawOffset = 0;
m_triangleDrawIndex = 0;
m_lineDrawIndex = 0;
m_pointDrawIndex = 0;
m_indexBuffers = new PID3D11Buffer[MAXVBUFFER_COUNT];
m_vertexBuffers = new PID3D11Buffer[MAXVBUFFER_COUNT];
for (m_activeIndexBuffer = 0; m_activeIndexBuffer < MAXVBUFFER_COUNT; m_activeIndexBuffer++)
m_vertex_draw_offset = 0;
m_triangle_draw_index = 0;
m_line_draw_index = 0;
m_point_draw_index = 0;
m_index_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
m_vertex_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
for (m_current_index_buffer = 0; m_current_index_buffer < MAX_VBUFFER_COUNT; m_current_index_buffer++)
{
m_indexBuffers[m_activeIndexBuffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_indexBuffers[m_activeIndexBuffer])),
m_index_buffers[m_current_index_buffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_index_buffers[m_current_index_buffer])),
"Failed to create index buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_indexBuffers[m_activeIndexBuffer], "index buffer of VertexManager");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_index_buffers[m_current_index_buffer], "index buffer of VertexManager");
}
bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufdesc.ByteWidth = VBUFFER_SIZE;
for (m_activeVertexBuffer = 0; m_activeVertexBuffer < MAXVBUFFER_COUNT; m_activeVertexBuffer++)
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
m_vertexBuffers[m_activeVertexBuffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_vertexBuffers[m_activeVertexBuffer])),
m_vertex_buffers[m_current_vertex_buffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_vertex_buffers[m_current_vertex_buffer])),
"Failed to create vertex buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vertexBuffers[m_activeVertexBuffer], "Vertex buffer of VertexManager");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vertex_buffers[m_current_vertex_buffer], "Vertex buffer of VertexManager");
}
m_activeVertexBuffer = 0;
m_activeIndexBuffer = 0;
m_indexBufferCursor = IBUFFER_SIZE;
m_vertexBufferCursor = VBUFFER_SIZE;
m_current_vertex_buffer = 0;
m_current_index_buffer = 0;
m_index_buffer_cursor = IBUFFER_SIZE;
m_vertex_buffer_cursor = VBUFFER_SIZE;
m_lineShader.Init();
m_pointShader.Init();
}
@@ -82,10 +82,10 @@ void VertexManager::DestroyDeviceObjects()
{
m_pointShader.Shutdown();
m_lineShader.Shutdown();
for (m_activeVertexBuffer = 0; m_activeVertexBuffer < MAXVBUFFER_COUNT; m_activeVertexBuffer++)
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
SAFE_RELEASE(m_vertexBuffers[m_activeVertexBuffer]);
SAFE_RELEASE(m_indexBuffers[m_activeVertexBuffer]);
SAFE_RELEASE(m_vertex_buffers[m_current_vertex_buffer]);
SAFE_RELEASE(m_index_buffers[m_current_vertex_buffer]);
}
}
@@ -100,47 +100,47 @@ VertexManager::~VertexManager()
DestroyDeviceObjects();
}
void VertexManager::LoadBuffers()
void VertexManager::PrepareDrawBuffers()
{
D3D11_MAPPED_SUBRESOURCE map;
UINT vSize = UINT(s_pCurBufferPointer - LocalVBuffer);
UINT vSize = UINT(s_pCurBufferPointer - s_pBaseBufferPointer);
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (m_vertexBufferCursor + vSize >= VBUFFER_SIZE)
if (m_vertex_buffer_cursor + vSize >= VBUFFER_SIZE)
{
// Wrap around
m_activeVertexBuffer = (m_activeVertexBuffer + 1) % MAXVBUFFER_COUNT;
m_vertexBufferCursor = 0;
m_current_vertex_buffer = (m_current_vertex_buffer + 1) % MAX_VBUFFER_COUNT;
m_vertex_buffer_cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
D3D::context->Map(m_vertexBuffers[m_activeVertexBuffer], 0, MapType, 0, &map);
D3D::context->Map(m_vertex_buffers[m_current_vertex_buffer], 0, MapType, 0, &map);
memcpy((u8*)map.pData + m_vertexBufferCursor, LocalVBuffer, vSize);
D3D::context->Unmap(m_vertexBuffers[m_activeVertexBuffer], 0);
m_vertexDrawOffset = m_vertexBufferCursor;
m_vertexBufferCursor += vSize;
memcpy((u8*)map.pData + m_vertex_buffer_cursor, s_pBaseBufferPointer, vSize);
D3D::context->Unmap(m_vertex_buffers[m_current_vertex_buffer], 0);
m_vertex_draw_offset = m_vertex_buffer_cursor;
m_vertex_buffer_cursor += vSize;
UINT iCount = IndexGenerator::GetTriangleindexLen() +
IndexGenerator::GetLineindexLen() + IndexGenerator::GetPointindexLen();
MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (m_indexBufferCursor + iCount >= (IBUFFER_SIZE / sizeof(u16)))
if (m_index_buffer_cursor + iCount >= (IBUFFER_SIZE / sizeof(u16)))
{
// Wrap around
m_activeIndexBuffer = (m_activeIndexBuffer + 1) % MAXVBUFFER_COUNT;
m_indexBufferCursor = 0;
m_current_index_buffer = (m_current_index_buffer + 1) % MAX_VBUFFER_COUNT;
m_index_buffer_cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
D3D::context->Map(m_indexBuffers[m_activeIndexBuffer], 0, MapType, 0, &map);
D3D::context->Map(m_index_buffers[m_current_index_buffer], 0, MapType, 0, &map);
m_triangleDrawIndex = m_indexBufferCursor;
m_lineDrawIndex = m_triangleDrawIndex + IndexGenerator::GetTriangleindexLen();
m_pointDrawIndex = m_lineDrawIndex + IndexGenerator::GetLineindexLen();
memcpy((u16*)map.pData + m_triangleDrawIndex, TIBuffer, sizeof(u16) * IndexGenerator::GetTriangleindexLen());
memcpy((u16*)map.pData + m_lineDrawIndex, LIBuffer, sizeof(u16) * IndexGenerator::GetLineindexLen());
memcpy((u16*)map.pData + m_pointDrawIndex, PIBuffer, sizeof(u16) * IndexGenerator::GetPointindexLen());
D3D::context->Unmap(m_indexBuffers[m_activeIndexBuffer], 0);
m_indexBufferCursor += iCount;
m_triangle_draw_index = m_index_buffer_cursor;
m_line_draw_index = m_triangle_draw_index + IndexGenerator::GetTriangleindexLen();
m_point_draw_index = m_line_draw_index + IndexGenerator::GetLineindexLen();
memcpy((u16*)map.pData + m_triangle_draw_index, GetTriangleIndexBuffer(), sizeof(u16) * IndexGenerator::GetTriangleindexLen());
memcpy((u16*)map.pData + m_line_draw_index, GetLineIndexBuffer(), sizeof(u16) * IndexGenerator::GetLineindexLen());
memcpy((u16*)map.pData + m_point_draw_index, GetPointIndexBuffer(), sizeof(u16) * IndexGenerator::GetPointindexLen());
D3D::context->Unmap(m_index_buffers[m_current_index_buffer], 0);
m_index_buffer_cursor += iCount;
}
static const float LINE_PT_TEX_OFFSETS[8] = {
@@ -149,13 +149,13 @@ static const float LINE_PT_TEX_OFFSETS[8] = {
void VertexManager::Draw(UINT stride)
{
D3D::context->IASetVertexBuffers(0, 1, &m_vertexBuffers[m_activeVertexBuffer], &stride, &m_vertexDrawOffset);
D3D::context->IASetIndexBuffer(m_indexBuffers[m_activeIndexBuffer], DXGI_FORMAT_R16_UINT, 0);
D3D::context->IASetVertexBuffers(0, 1, &m_vertex_buffers[m_current_vertex_buffer], &stride, &m_vertex_draw_offset);
D3D::context->IASetIndexBuffer(m_index_buffers[m_current_index_buffer], DXGI_FORMAT_R16_UINT, 0);
if (IndexGenerator::GetNumTriangles() > 0)
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D::context->DrawIndexed(IndexGenerator::GetTriangleindexLen(), m_triangleDrawIndex, 0);
D3D::context->DrawIndexed(IndexGenerator::GetTriangleindexLen(), m_triangle_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
// Disable culling for lines and points
@@ -177,7 +177,7 @@ void VertexManager::Draw(UINT stride)
texOffset, vpWidth, vpHeight, texOffsetEnable))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_lineDrawIndex, 0);
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_line_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
@@ -199,7 +199,7 @@ void VertexManager::Draw(UINT stride)
texOffset, vpWidth, vpHeight, texOffsetEnable))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_pointDrawIndex, 0);
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_point_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
@@ -211,11 +211,6 @@ void VertexManager::Draw(UINT stride)
void VertexManager::vFlush()
{
if (LocalVBuffer == s_pCurBufferPointer) return;
if (Flushed) return;
Flushed=true;
VideoFifo_CheckEFBAccess();
u32 usedtextures = 0;
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevorders[i / 2].getEnable(i & 1))
@@ -237,8 +232,8 @@ void VertexManager::vFlush()
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),
tex.texMode1[i&3].max_lod >> 4,
(tex.texMode0[i&3].min_filter & 3),
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
tex.texImage1[i&3].image_type);
if (tentry)
@@ -263,26 +258,25 @@ void VertexManager::vFlush()
g_nativeVertexFmt->m_components))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
goto shader_fail;
return;
}
if (!VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
goto shader_fail;
return;
}
LoadBuffers();
PrepareDrawBuffers();
unsigned int stride = g_nativeVertexFmt->GetVertexStride();
g_nativeVertexFmt->SetupVertexPointers();
g_renderer->ApplyState(useDstAlpha);
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
Draw(stride);
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
g_renderer->RestoreState();
shader_fail:
ResetBuffer();
}
} // namespace
@@ -37,22 +37,22 @@ public:
private:
void LoadBuffers();
void Draw(UINT stride);
void PrepareDrawBuffers();
void Draw(u32 stride);
// temp
void vFlush();
UINT m_indexBufferCursor;
UINT m_vertexBufferCursor;
UINT m_vertexDrawOffset;
UINT m_triangleDrawIndex;
UINT m_lineDrawIndex;
UINT m_pointDrawIndex;
UINT m_activeVertexBuffer;
UINT m_activeIndexBuffer;
u32 m_vertex_buffer_cursor;
u32 m_vertex_draw_offset;
u32 m_index_buffer_cursor;
u32 m_current_vertex_buffer;
u32 m_current_index_buffer;
u32 m_triangle_draw_index;
u32 m_line_draw_index;
u32 m_point_draw_index;
typedef ID3D11Buffer* PID3D11Buffer;
PID3D11Buffer* m_indexBuffers;
PID3D11Buffer* m_vertexBuffers;
PID3D11Buffer* m_index_buffers;
PID3D11Buffer* m_vertex_buffers;
LineGeometryShader m_lineShader;
PointGeometryShader m_pointShader;
@@ -162,7 +162,7 @@ void VertexShaderCache::Init()
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;
vs_constant_offset_table[C_DEPTHPARAMS] = 952;
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
@@ -15,6 +15,7 @@ class VideoBackend : public VideoBackendHardware
std::string GetName();
void Video_Prepare();
void Video_Cleanup();
void ShowConfig(void* parent);
+10 -4
View File
@@ -42,6 +42,7 @@
#include "D3DUtil.h"
#include "D3DBase.h"
#include "PerfQuery.h"
#include "PixelShaderCache.h"
#include "TextureCache.h"
#include "VertexManager.h"
@@ -90,6 +91,7 @@ void InitBackendInfo()
g_Config.backend_info.APIType = API_D3D11;
g_Config.backend_info.bUseRGBATextures = true; // the GX formats barely match any D3D11 formats
g_Config.backend_info.bUseMinimalMipCount = true;
g_Config.backend_info.bSupports3DVision = false;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsFormatReinterpretation = true;
@@ -101,15 +103,13 @@ void InitBackendInfo()
if (FAILED(hr))
PanicAlert("Failed to create IDXGIFactory object");
char tmpstr[512] = {};
DXGI_ADAPTER_DESC desc;
// adapters
g_Config.backend_info.Adapters.clear();
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC desc;
ad->GetDesc(&desc);
WideCharToMultiByte(/*CP_UTF8*/CP_ACP, 0, desc.Description, -1, tmpstr, 512, 0, false);
// TODO: These don't get updated on adapter change, yet
if (g_Config.backend_info.Adapters.size() == g_Config.iAdapter)
@@ -126,7 +126,7 @@ void InitBackendInfo()
}
}
g_Config.backend_info.Adapters.push_back(tmpstr);
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release();
}
@@ -184,6 +184,7 @@ void VideoBackend::Video_Prepare()
g_renderer = new Renderer;
g_texture_cache = new TextureCache;
g_vertex_manager = new VertexManager;
g_perf_query = new PerfQuery;
VertexShaderCache::Init();
PixelShaderCache::Init();
D3D::InitUtils();
@@ -207,6 +208,7 @@ void VideoBackend::Shutdown()
{
s_BackendInitialized = false;
// TODO: should be in Video_Cleanup
if (g_renderer)
{
s_efbAccessRequested = FALSE;
@@ -226,6 +228,7 @@ void VideoBackend::Shutdown()
D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
delete g_perf_query;
delete g_vertex_manager;
delete g_texture_cache;
delete g_renderer;
@@ -234,4 +237,7 @@ void VideoBackend::Shutdown()
}
}
void VideoBackend::Video_Cleanup() {
}
}
+173 -55
View File
@@ -66,6 +66,7 @@ static int numAdapters;
static int cur_adapter;
// Value caches for state filtering
const int MaxStreamSources = 16;
const int MaxTextureStages = 9;
const int MaxRenderStates = 210 + 46;
const int MaxTextureTypes = 33;
@@ -83,10 +84,23 @@ 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;
static LPDIRECT3DBASETEXTURE9 m_Textures[16];
static LPDIRECT3DVERTEXDECLARATION9 m_VtxDecl;
static bool m_VtxDeclChanged;
static LPDIRECT3DPIXELSHADER9 m_PixelShader;
static bool m_PixelShaderChanged;
static LPDIRECT3DVERTEXSHADER9 m_VertexShader;
static bool m_VertexShaderChanged;
struct StreamSourceDescriptor
{
LPDIRECT3DVERTEXBUFFER9 pStreamData;
UINT OffsetInBytes;
UINT Stride;
};
static StreamSourceDescriptor m_stream_sources[MaxStreamSources];
static bool m_stream_sources_Changed[MaxStreamSources];
static LPDIRECT3DINDEXBUFFER9 m_index_buffer;
static bool m_index_buffer_Changed;
// Z buffer formats to be used for EFB depth surface
D3DFORMAT DepthFormats[] = {
@@ -170,9 +184,9 @@ 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'));
SetRenderState(D3DRS_POINTSIZE, (D3DFORMAT)MAKEFOURCC('A', '2', 'M', '1'));
else
D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C'));
SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C'));
}
void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp)
@@ -209,20 +223,20 @@ void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp)
yres = pp->BackBufferHeight = client.bottom - client.top;
}
pp->SwapEffect = D3DSWAPEFFECT_DISCARD;
pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
pp->PresentationInterval = g_Config.IsVSync() ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
pp->Windowed = !g_Config.b3DVision;
}
void Enumerate()
{
numAdapters = D3D::D3D->GetAdapterCount();
numAdapters = 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);
D3D->GetAdapterIdentifier(i, 0, &a.ident);
bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA;
// Add SuperSamples modes
@@ -233,17 +247,17 @@ void Enumerate()
//disable them will they are not implemnted
/*
DWORD qlevels = 0;
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
if (D3DERR_NOTAVAILABLE != 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(
if (D3DERR_NOTAVAILABLE != 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(
if (D3DERR_NOTAVAILABLE != 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));
@@ -251,7 +265,7 @@ void Enumerate()
if (isNvidia)
{
// CSAA support
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
if (D3DERR_NOTAVAILABLE != D3D->CheckDeviceMultiSampleType(
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels))
{
if (qlevels > 2)
@@ -262,7 +276,7 @@ void Enumerate()
a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0));
}
}
if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
if (D3DERR_NOTAVAILABLE != D3D->CheckDeviceMultiSampleType(
i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels))
{
if (qlevels > 2)
@@ -296,11 +310,11 @@ void Enumerate()
{
strcpy(a.aa_levels[0].name, "(Not supported on this device)");
}
int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8);
int numModes = D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8);
for (int m = 0; m < numModes; m++)
{
D3DDISPLAYMODE mode;
D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode);
D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode);
int found = -1;
for (int x = 0; x < (int)a.resolutions.size(); x++)
@@ -440,8 +454,8 @@ HRESULT Create(int adapter, HWND wnd, int _resolution, int aa_mode, bool auto_de
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);
SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE );
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));
@@ -452,6 +466,15 @@ HRESULT Create(int adapter, HWND wnd, int _resolution, int aa_mode, bool auto_de
m_VtxDecl = NULL;
m_PixelShader = NULL;
m_VertexShader = NULL;
m_index_buffer = NULL;
memset(m_stream_sources, 0, sizeof(m_stream_sources));
m_index_buffer = NULL;
m_VtxDeclChanged = false;
m_PixelShaderChanged = false;
m_VertexShaderChanged = false;
memset(m_stream_sources_Changed, 0 , sizeof(m_stream_sources_Changed));
m_index_buffer_Changed = false;
// Device state would normally be set here
return S_OK;
}
@@ -516,7 +539,7 @@ bool CheckDepthStencilSupport(D3DFORMAT target_format, D3DFORMAT depth_format)
D3DFORMAT GetSupportedDepthTextureFormat()
{
for (int i = 0; i < sizeof(DepthFormats)/sizeof(D3DFORMAT); ++i)
if (D3D::CheckTextureSupport(D3DUSAGE_DEPTHSTENCIL, DepthFormats[i]))
if (CheckTextureSupport(D3DUSAGE_DEPTHSTENCIL, DepthFormats[i]))
return DepthFormats[i];
return D3DFMT_UNKNOWN;
@@ -525,7 +548,7 @@ D3DFORMAT GetSupportedDepthTextureFormat()
D3DFORMAT GetSupportedDepthSurfaceFormat(D3DFORMAT target_format)
{
for (int i = 0; i < sizeof(DepthFormats)/sizeof(D3DFORMAT); ++i)
if (D3D::CheckDepthStencilSupport(target_format, DepthFormats[i]))
if (CheckDepthStencilSupport(target_format, DepthFormats[i]))
return DepthFormats[i];
return D3DFMT_UNKNOWN;
@@ -533,13 +556,13 @@ D3DFORMAT GetSupportedDepthSurfaceFormat(D3DFORMAT target_format)
const char *VertexShaderVersionString()
{
int version = ((D3D::caps.VertexShaderVersion >> 8) & 0xFF);
int version = ((caps.VertexShaderVersion >> 8) & 0xFF);
return vsVersions[std::min(4, version)];
}
const char *PixelShaderVersionString()
{
int version = ((D3D::caps.PixelShaderVersion >> 8) & 0xFF);
int version = ((caps.PixelShaderVersion >> 8) & 0xFF);
return psVersions[std::min(4, version)];
}
@@ -653,14 +676,14 @@ void ApplyCachedState()
for (int type = 0; type < MaxSamplerTypes; type++)
{
if(m_SamplerStatesSet[sampler][type])
D3D::dev->SetSamplerState(sampler, (D3DSAMPLERSTATETYPE)type, m_SamplerStates[sampler][type]);
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]);
dev->SetRenderState((D3DRENDERSTATETYPE)rs, m_RenderStates[rs]);
}
// We don't bother restoring these so let's just wipe the state copy
@@ -671,6 +694,13 @@ void ApplyCachedState()
m_VtxDecl = NULL;
m_PixelShader = NULL;
m_VertexShader = NULL;
memset(m_stream_sources, 0, sizeof(m_stream_sources));
m_index_buffer = NULL;
m_VtxDeclChanged = false;
m_PixelShaderChanged = false;
m_VertexShaderChanged = false;
memset(m_stream_sources_Changed, 0 , sizeof(m_stream_sources_Changed));
m_index_buffer_Changed = false;
}
void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture)
@@ -678,7 +708,7 @@ void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture)
if (m_Textures[Stage] != pTexture)
{
m_Textures[Stage] = pTexture;
D3D::dev->SetTexture(Stage, pTexture);
dev->SetTexture(Stage, pTexture);
}
}
@@ -686,7 +716,7 @@ void RefreshRenderState(D3DRENDERSTATETYPE State)
{
if(m_RenderStatesSet[State] && m_RenderStatesChanged[State])
{
D3D::dev->SetRenderState(State, m_RenderStates[State]);
dev->SetRenderState(State, m_RenderStates[State]);
m_RenderStatesChanged[State] = false;
}
}
@@ -698,7 +728,7 @@ void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value)
m_RenderStates[State] = Value;
m_RenderStatesSet[State] = true;
m_RenderStatesChanged[State] = false;
D3D::dev->SetRenderState(State, Value);
dev->SetRenderState(State, Value);
}
}
@@ -707,7 +737,7 @@ 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);
dev->SetRenderState(State, Value);
}
else
{
@@ -722,7 +752,7 @@ void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Valu
m_TextureStageStates[Stage][Type] = Value;
m_TextureStageStatesSet[Stage][Type]=true;
m_TextureStageStatesChanged[Stage][Type]=false;
D3D::dev->SetTextureStageState(Stage, Type, Value);
dev->SetTextureStageState(Stage, Type, Value);
}
}
@@ -730,7 +760,7 @@ void RefreshTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type)
{
if(m_TextureStageStatesSet[Stage][Type] && m_TextureStageStatesChanged[Stage][Type])
{
D3D::dev->SetTextureStageState(Stage, Type, m_TextureStageStates[Stage][Type]);
dev->SetTextureStageState(Stage, Type, m_TextureStageStates[Stage][Type]);
m_TextureStageStatesChanged[Stage][Type] = false;
}
}
@@ -740,7 +770,7 @@ void ChangeTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD V
if (m_TextureStageStates[Stage][Type] != Value || !m_TextureStageStatesSet[Stage][Type])
{
m_TextureStageStatesChanged[Stage][Type] = m_TextureStageStatesSet[Stage][Type];
D3D::dev->SetTextureStageState(Stage, Type, Value);
dev->SetTextureStageState(Stage, Type, Value);
}
else
{
@@ -755,7 +785,7 @@ void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
m_SamplerStates[Sampler][Type] = Value;
m_SamplerStatesSet[Sampler][Type] = true;
m_SamplerStatesChanged[Sampler][Type] = false;
D3D::dev->SetSamplerState(Sampler, Type, Value);
dev->SetSamplerState(Sampler, Type, Value);
}
}
@@ -763,7 +793,7 @@ void RefreshSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type)
{
if(m_SamplerStatesSet[Sampler][Type] && m_SamplerStatesChanged[Sampler][Type])
{
D3D::dev->SetSamplerState(Sampler, Type, m_SamplerStates[Sampler][Type]);
dev->SetSamplerState(Sampler, Type, m_SamplerStates[Sampler][Type]);
m_SamplerStatesChanged[Sampler][Type] = false;
}
}
@@ -773,7 +803,7 @@ 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);
dev->SetSamplerState(Sampler, Type, Value);
}
else
{
@@ -783,67 +813,155 @@ void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value)
void RefreshVertexDeclaration()
{
if (m_VtxDecl)
if (m_VtxDeclChanged)
{
D3D::dev->SetVertexDeclaration(m_VtxDecl);
dev->SetVertexDeclaration(m_VtxDecl);
m_VtxDeclChanged = false;
}
}
void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl)
{
if (!decl) {
m_VtxDecl = NULL;
return;
}
if (decl != m_VtxDecl)
{
D3D::dev->SetVertexDeclaration(decl);
dev->SetVertexDeclaration(decl);
m_VtxDecl = decl;
m_VtxDeclChanged = false;
}
}
void ChangeVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl)
{
if (decl != m_VtxDecl) {
dev->SetVertexDeclaration(decl);
m_VtxDeclChanged = true;
}
}
void ChangeVertexShader(LPDIRECT3DVERTEXSHADER9 shader)
{
if (shader != m_VertexShader)
{
dev->SetVertexShader(shader);
m_VertexShaderChanged = true;
}
}
void RefreshVertexShader()
{
if (m_VertexShader)
if (m_VertexShaderChanged)
{
D3D::dev->SetVertexShader(m_VertexShader);
dev->SetVertexShader(m_VertexShader);
m_VertexShaderChanged = false;
}
}
void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader)
{
if (!shader) {
m_VertexShader = NULL;
return;
}
if (shader != m_VertexShader)
{
D3D::dev->SetVertexShader(shader);
dev->SetVertexShader(shader);
m_VertexShader = shader;
m_VertexShaderChanged = false;
}
}
void RefreshPixelShader()
{
if (m_PixelShader)
if (m_PixelShaderChanged)
{
D3D::dev->SetPixelShader(m_PixelShader);
dev->SetPixelShader(m_PixelShader);
m_PixelShaderChanged = false;
}
}
void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader)
{
if (!shader) {
m_PixelShader = NULL;
return;
}
if (shader != m_PixelShader)
{
D3D::dev->SetPixelShader(shader);
dev->SetPixelShader(shader);
m_PixelShader = shader;
m_PixelShaderChanged = false;
}
}
void ChangePixelShader(LPDIRECT3DPIXELSHADER9 shader)
{
if (shader != m_PixelShader)
{
dev->SetPixelShader(shader);
m_PixelShaderChanged = true;
}
}
void SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride)
{
if (m_stream_sources[StreamNumber].OffsetInBytes != OffsetInBytes
|| m_stream_sources[StreamNumber].pStreamData != pStreamData
|| m_stream_sources[StreamNumber].Stride != Stride)
{
m_stream_sources[StreamNumber].OffsetInBytes = OffsetInBytes;
m_stream_sources[StreamNumber].pStreamData = pStreamData;
m_stream_sources[StreamNumber].Stride = Stride;
dev->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride);
m_stream_sources_Changed[StreamNumber] = false;
}
}
void ChangeStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride)
{
if (m_stream_sources[StreamNumber].OffsetInBytes != OffsetInBytes
|| m_stream_sources[StreamNumber].pStreamData != pStreamData
|| m_stream_sources[StreamNumber].Stride != Stride)
{
dev->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride);
m_stream_sources_Changed[StreamNumber] = true;
}
}
void RefreshStreamSource(UINT StreamNumber)
{
if (m_PixelShaderChanged)
{
dev->SetStreamSource(
StreamNumber,
m_stream_sources[StreamNumber].pStreamData,
m_stream_sources[StreamNumber].OffsetInBytes,
m_stream_sources[StreamNumber].Stride);
m_stream_sources_Changed[StreamNumber] = false;
}
}
void SetIndices(LPDIRECT3DINDEXBUFFER9 pIndexData)
{
if(pIndexData != m_index_buffer)
{
m_index_buffer = pIndexData;
dev->SetIndices(pIndexData);
m_index_buffer_Changed = false;
}
}
void ChangeIndices(LPDIRECT3DINDEXBUFFER9 pIndexData)
{
if(pIndexData != m_index_buffer)
{
dev->SetIndices(pIndexData);
m_index_buffer_Changed = true;
}
}
void RefreshIndices()
{
if (m_index_buffer_Changed)
{
dev->SetIndices(m_index_buffer);
m_index_buffer_Changed = false;
}
}
} // namespace
@@ -100,12 +100,23 @@ void ChangeSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
void RefreshVertexDeclaration();
void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl);
void ChangeVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl);
void RefreshVertexShader();
void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader);
void ChangeVertexShader(LPDIRECT3DVERTEXSHADER9 shader);
void RefreshPixelShader();
void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader);
void ChangePixelShader(LPDIRECT3DPIXELSHADER9 shader);
void SetStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride);
void ChangeStreamSource(UINT StreamNumber,IDirect3DVertexBuffer9* pStreamData,UINT OffsetInBytes,UINT Stride);
void RefreshStreamSource(UINT StreamNumber);
void SetIndices(LPDIRECT3DINDEXBUFFER9 pIndexData);
void ChangeIndices(LPDIRECT3DINDEXBUFFER9 pIndexData);
void RefreshIndices();
void ApplyCachedState();
@@ -50,7 +50,8 @@ bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecode
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
@@ -105,7 +106,8 @@ bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodel
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
+18 -12
View File
@@ -198,6 +198,8 @@ const int TS[6][2] =
void RestoreShaders()
{
D3D::SetTexture(0, 0);
D3D::RefreshStreamSource(0);
D3D::RefreshIndices();
D3D::RefreshVertexDeclaration();
D3D::RefreshPixelShader();
D3D::RefreshVertexShader();
@@ -217,9 +219,9 @@ void CD3DFont::SetRenderStates()
{
D3D::SetTexture(0, m_pTexture);
dev->SetPixelShader(0);
dev->SetVertexShader(0);
D3D::ChangePixelShader(0);
D3D::ChangeVertexShader(0);
D3D::ChangeVertexDeclaration(0);
dev->SetFVF(D3DFVF_FONT2DVERTEX);
for (int i = 0; i < 6; i++)
@@ -236,7 +238,7 @@ int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, flo
return 0;
SetRenderStates();
dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX));
D3D::ChangeStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX));
float vpWidth = 1;
float vpHeight = 1;
@@ -389,9 +391,10 @@ void drawShadedTexQuad(IDirect3DTexture9 *texture,
{ 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, sw, sh, g},
{ 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, sw, sh, g}
};
dev->SetVertexShader(Vshader);
dev->SetPixelShader(PShader);
D3D::ChangeVertexShader(Vshader);
D3D::ChangePixelShader(PShader);
D3D::SetTexture(0, texture);
D3D::ChangeVertexDeclaration(0);
dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE1(2));
dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
RestoreShaders();
@@ -424,9 +427,10 @@ void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
{ rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, sw, sh, g},
{ rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, sw, sh, g}
};
dev->SetVertexShader(Vshader);
dev->SetPixelShader(PShader);
D3D::ChangeVertexShader(Vshader);
D3D::ChangePixelShader(PShader);
D3D::SetTexture(0, texture);
D3D::ChangeVertexDeclaration(0);
dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE1(2));
dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
RestoreShaders();
@@ -442,8 +446,9 @@ void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2)
{ x1, y1, 0.f, 1.f, Color },
{ x2, y1, 0.f, 1.f, Color },
};
dev->SetVertexShader(VertexShaderCache::GetClearVertexShader());
dev->SetPixelShader(PixelShaderCache::GetClearProgram());
D3D::ChangeVertexShader(VertexShaderCache::GetClearVertexShader());
D3D::ChangePixelShader(PixelShaderCache::GetClearProgram());
D3D::ChangeVertexDeclaration(0);
dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE);
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(CQVertex));
RestoreShaders();
@@ -457,8 +462,9 @@ void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVer
{ 1.0f, -1.0f, z, 1.0f, Color},
{-1.0f, -1.0f, z, 1.0f, Color}
};
dev->SetVertexShader(Vshader);
dev->SetPixelShader(PShader);
D3D::ChangeVertexShader(Vshader);
D3D::ChangePixelShader(PShader);
D3D::ChangeVertexDeclaration(0);
dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE);
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex));
RestoreShaders();
@@ -187,6 +187,8 @@ void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState(); // reset any game specific settings
// Copy EFB data to XFB and restore render target again
LPDIRECT3DSURFACE9 Rendersurf = NULL;
texture->GetSurfaceLevel(0, &Rendersurf);
@@ -229,6 +231,8 @@ void XFBSource::CopyEFB(float Gamma)
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
Rendersurf->Release();
g_renderer->RestoreAPIState();
}
} // namespace DX9
@@ -19,7 +19,7 @@
#include "D3DBase.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "MemoryUtil.h"
#include "VertexShaderGen.h"
+168 -168
View File
@@ -67,154 +67,13 @@ static int s_fps = 0;
static u32 s_blendMode;
static u32 s_LastAA;
static bool IS_AMD;
static float m_fMaxPointSize;
static char *st;
static LPDIRECT3DSURFACE9 ScreenShootMEMSurface = NULL;
// 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
};
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
static const 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 SetupDeviceObjects()
{
D3D::font.Init();
@@ -329,6 +188,9 @@ Renderer::Renderer()
D3D::BeginFrame();
D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true);
D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL );
D3D::SetRenderState(D3DRS_POINTSCALEENABLE,false);
m_fMaxPointSize = D3D::GetCaps().MaxPointSize;
}
Renderer::~Renderer()
@@ -358,11 +220,11 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
}
void formatBufferDump(const char *in, char *out, int w, int h, int p)
void formatBufferDump(const u8* in, u8* out, int w, int h, int p)
{
for (int y = 0; y < h; y++)
{
const char *line = in + (h - y - 1) * p;
auto line = in + (h - y - 1) * p;
for (int x = 0; x < w; x++)
{
memcpy(out, line, 3);
@@ -796,6 +658,32 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
void Renderer::SetBlendMode(bool forceUpdate)
{
// Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel
// Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1.
bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
const D3DBLEND d3dSrcFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
(target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE,
(target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
const D3DBLEND d3dDestFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
(target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE,
(target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO
};
if (bpmem.blendmode.logicopenable && !forceUpdate)
return;
@@ -808,8 +696,8 @@ void Renderer::SetBlendMode(bool forceUpdate)
}
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_ALPHABLENDENABLE, bpmem.blendmode.blendenable);
if (bpmem.blendmode.blendenable)
{
D3D::SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[bpmem.blendmode.srcfactor]);
@@ -841,8 +729,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
if (g_bSkipCurrentFrame || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{
if (g_ActiveConfig.bDumpFrames && frame_data)
AVIDump::AddFrame(frame_data);
if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false);
return;
@@ -853,8 +741,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
{
if (g_ActiveConfig.bDumpFrames && frame_data)
AVIDump::AddFrame(frame_data);
if (g_ActiveConfig.bDumpFrames && !frame_data.empty())
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
Core::Callback_VideoCopiedToXFB(false);
return;
@@ -1051,15 +939,14 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
D3DLOCKED_RECT rect;
if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, GetTargetRectangle().AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY)))
{
if (!frame_data || w != s_recordWidth || h != s_recordHeight)
if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight)
{
delete[] frame_data;
frame_data = new char[3 * s_recordWidth * s_recordHeight];
frame_data.resize(3 * s_recordWidth * s_recordHeight);
w = s_recordWidth;
h = s_recordHeight;
}
formatBufferDump((const char*)rect.pBits, frame_data, s_recordWidth, s_recordHeight, rect.Pitch);
AVIDump::AddFrame(frame_data);
formatBufferDump((const u8*)rect.pBits, &frame_data[0], s_recordWidth, s_recordHeight, rect.Pitch);
AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight);
ScreenShootMEMSurface->UnlockRect();
}
}
@@ -1069,12 +956,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
{
if (bLastFrameDumped && bAVIDumping)
{
if (frame_data)
{
delete[] frame_data;
frame_data = 0;
w = h = 0;
}
std::vector<u8>().swap(frame_data);
w = h = 0;
AVIDump::Stop();
bAVIDumping = false;
OSD::AddMessage("Stop dumping frames to AVI", 2000);
@@ -1261,11 +1144,31 @@ void Renderer::RestoreAPIState()
void Renderer::SetGenerationMode()
{
const D3DCULL d3dCullModes[4] =
{
D3DCULL_NONE,
D3DCULL_CCW,
D3DCULL_CW,
D3DCULL_CCW
};
D3D::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
}
void Renderer::SetDepthMode()
{
const D3DCMPFUNC d3dCmpFuncs[8] =
{
D3DCMP_NEVER,
D3DCMP_LESS,
D3DCMP_EQUAL,
D3DCMP_LESSEQUAL,
D3DCMP_GREATER,
D3DCMP_NOTEQUAL,
D3DCMP_GREATEREQUAL,
D3DCMP_ALWAYS
};
if (bpmem.zmode.testenable)
{
D3D::SetRenderState(D3DRS_ZENABLE, TRUE);
@@ -1282,7 +1185,83 @@ void Renderer::SetDepthMode()
void Renderer::SetLogicOpMode()
{
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
// D3D9 doesn't support logic blending, so this is a huge hack
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
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
};
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
};
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
};
if (bpmem.blendmode.logicopenable)
{
D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, true);
D3D::SetRenderState(D3DRS_BLENDOP, d3dLogicOpop[bpmem.blendmode.logicmode]);
@@ -1305,11 +1284,34 @@ void Renderer::SetLineWidth()
// We can't change line width in D3D unless we use ID3DXLine
float fratio = xfregs.viewport.wd != 0 ? Renderer::EFBToScaledXf(1.f) : 1.0f;
float psize = bpmem.lineptwidth.linesize * fratio / 6.0f;
//little hack to compensate scalling problems in dx9 must be taken out when scalling is fixed.
psize *= 2.0f;
if (psize > m_fMaxPointSize)
{
psize = m_fMaxPointSize;
}
D3D::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize));
D3D::SetRenderState(D3DRS_POINTSIZE_MIN, *((DWORD*)&psize));
D3D::SetRenderState(D3DRS_POINTSIZE_MAX, *((DWORD*)&psize));
}
void Renderer::SetSamplerState(int stage, int texindex)
{
const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
{
D3DTEXF_NONE,
D3DTEXF_POINT,
D3DTEXF_LINEAR,
D3DTEXF_NONE, //reserved
};
const D3DTEXTUREADDRESS d3dClamps[4] =
{
D3DTADDRESS_CLAMP,
D3DTADDRESS_WRAP,
D3DTADDRESS_MIRROR,
D3DTADDRESS_WRAP //reserved
};
const FourTexUnits &tex = bpmem.tex[texindex];
const TexMode0 &tm0 = tex.texMode0[stage];
const TexMode1 &tm1 = tex.texMode1[stage];
@@ -1323,13 +1325,11 @@ void Renderer::SetSamplerState(int stage, int texindex)
{
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;
mip = d3dMipFilters[tm0.min_filter & 3];
}
if (texindex)
stage += 4;
if (mag == D3DTEXF_LINEAR && min == D3DTEXF_LINEAR && g_ActiveConfig.iMaxAnisotropy)
{
min = D3DTEXF_ANISOTROPIC;
@@ -1340,8 +1340,8 @@ void Renderer::SetSamplerState(int stage, int texindex)
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;
float lodbias = (s32)tm0.lod_bias / 32.0f;
D3D::SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lodbias);
D3D::SetSamplerState(stage, D3DSAMP_MAXMIPLEVEL, tm1.min_lod >> 4);
}
@@ -72,10 +72,9 @@ bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips)
unsigned int expanded_width, unsigned int level)
{
D3D::ReplaceTexture2D(texture, temp, width, height, expanded_width, d3d_fmt, swap_r_b, level);
// D3D9 will automatically generate mip maps if necessary
}
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
@@ -83,6 +82,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat)
{
g_renderer->ResetAPIState(); // reset any game specific settings
const LPDIRECT3DTEXTURE9 read_texture = (srcFormat == PIXELFMT_Z24) ?
FramebufferManager::GetEFBDepthTexture() :
FramebufferManager::GetEFBColorTexture();
@@ -180,6 +181,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
D3D::SetTexture(0, NULL);
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface());
g_renderer->RestoreAPIState();
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height,
@@ -227,6 +230,8 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, u
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;
entry->Load(width, height, expanded_width, 0);
return entry;
}
@@ -44,7 +44,7 @@ private:
~TCacheEntry();
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels, bool autogen_mips = false);
unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
@@ -42,9 +42,9 @@ extern NativeVertexFormat *g_nativeVertexFmt;
namespace DX9
{
//This are the initially requeted size for the buffers expresed in elements
const u32 IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * 16;
const u32 VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE * 16;
const u32 MAXVBUFFER_COUNT = 2;
const u32 IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
const u32 VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
const u32 MAX_VBUFFER_COUNT = 2;
inline void DumpBadShaders()
{
@@ -67,88 +67,88 @@ inline void DumpBadShaders()
void VertexManager::CreateDeviceObjects()
{
NumVBuffers = 0;
VBuffers = NULL;
IBuffers = NULL;
m_buffers_count = 0;
m_vertex_buffers = NULL;
m_index_buffers = NULL;
D3DCAPS9 DeviceCaps = D3D::GetCaps();
u32 devicevMaxBufferSize = DeviceCaps.MaxPrimitiveCount * 3 * DeviceCaps.MaxStreamStride;
//Calculate Device Dependant size
CurrentVBufferSize = (VBUFFER_SIZE > devicevMaxBufferSize) ? devicevMaxBufferSize : VBUFFER_SIZE;
CurrentIBufferSize = (IBUFFER_SIZE > DeviceCaps.MaxVertexIndex) ? DeviceCaps.MaxVertexIndex : IBUFFER_SIZE;
m_vertex_buffer_size = (VBUFFER_SIZE > devicevMaxBufferSize) ? devicevMaxBufferSize : VBUFFER_SIZE;
m_index_buffer_size = (IBUFFER_SIZE > DeviceCaps.MaxVertexIndex) ? DeviceCaps.MaxVertexIndex : IBUFFER_SIZE;
//if device caps are not enough for Vbuffer fall back to vertex arrays
if (CurrentIBufferSize < MAXIBUFFERSIZE || CurrentVBufferSize < MAXVBUFFERSIZE) return;
if (m_index_buffer_size < MAXIBUFFERSIZE || m_vertex_buffer_size < MAXVBUFFERSIZE) return;
VBuffers = new LPDIRECT3DVERTEXBUFFER9[MAXVBUFFER_COUNT];
IBuffers = new LPDIRECT3DINDEXBUFFER9[MAXVBUFFER_COUNT];
m_vertex_buffers = new LPDIRECT3DVERTEXBUFFER9[MAX_VBUFFER_COUNT];
m_index_buffers = new LPDIRECT3DINDEXBUFFER9[MAX_VBUFFER_COUNT];
bool Fail = false;
for (CurrentVBuffer = 0; CurrentVBuffer < MAXVBUFFER_COUNT; CurrentVBuffer++)
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
VBuffers[CurrentVBuffer] = NULL;
IBuffers[CurrentVBuffer] = NULL;
m_vertex_buffers[m_current_vertex_buffer] = NULL;
m_index_buffers[m_current_vertex_buffer] = NULL;
}
for (CurrentVBuffer = 0; CurrentVBuffer < MAXVBUFFER_COUNT; CurrentVBuffer++)
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
if(FAILED( D3D::dev->CreateVertexBuffer( CurrentVBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &VBuffers[CurrentVBuffer], NULL ) ) )
if(FAILED( D3D::dev->CreateVertexBuffer( m_vertex_buffer_size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &m_vertex_buffers[m_current_vertex_buffer], NULL ) ) )
{
Fail = true;
break;
}
if( FAILED( D3D::dev->CreateIndexBuffer( CurrentIBufferSize * sizeof(u16), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &IBuffers[CurrentVBuffer], NULL ) ) )
if( FAILED( D3D::dev->CreateIndexBuffer( m_index_buffer_size * sizeof(u16), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_index_buffers[m_current_vertex_buffer], NULL ) ) )
{
Fail = true;
return;
}
}
NumVBuffers = CurrentVBuffer;
CurrentVBuffer = 0;
CurrentIBuffer = 0;
CurrentIBufferIndex = CurrentIBufferSize;
CurrentVBufferIndex = CurrentVBufferSize;
m_buffers_count = m_current_vertex_buffer;
m_current_vertex_buffer = 0;
m_current_index_buffer = 0;
m_index_buffer_cursor = m_index_buffer_size;
m_vertex_buffer_cursor = m_vertex_buffer_size;
m_current_stride = 0;
if (Fail)
{
NumVBuffers--;
if (NumVBuffers < 2)
m_buffers_count--;
if (m_buffers_count < 2)
{
//Error creating Vertex buffers. clean and fall to Vertex arrays
NumVBuffers = MAXVBUFFER_COUNT;
m_buffers_count = MAX_VBUFFER_COUNT;
DestroyDeviceObjects();
}
}
}
void VertexManager::DestroyDeviceObjects()
{
D3D::dev->SetStreamSource( 0, NULL, 0, 0);
D3D::dev->SetIndices(NULL);
for (int i = 0; i < MAXVBUFFER_COUNT; i++)
D3D::SetStreamSource( 0, NULL, 0, 0);
D3D::SetIndices(NULL);
for (int i = 0; i < MAX_VBUFFER_COUNT; i++)
{
if(VBuffers)
if(m_vertex_buffers)
{
if (VBuffers[i])
if (m_vertex_buffers[i])
{
VBuffers[i]->Release();
VBuffers[i] = NULL;
m_vertex_buffers[i]->Release();
m_vertex_buffers[i] = NULL;
}
}
if (IBuffers[i])
if (m_index_buffers[i])
{
IBuffers[i]->Release();
IBuffers[i] = NULL;
m_index_buffers[i]->Release();
m_index_buffers[i] = NULL;
}
}
if(VBuffers)
delete [] VBuffers;
if(IBuffers)
delete [] IBuffers;
VBuffers = NULL;
IBuffers = NULL;
if(m_vertex_buffers)
delete [] m_vertex_buffers;
if(m_index_buffers)
delete [] m_index_buffers;
m_vertex_buffers = NULL;
m_index_buffers = NULL;
}
void VertexManager::PrepareVBuffers(int stride)
void VertexManager::PrepareDrawBuffers(u32 stride)
{
if (!NumVBuffers)
if (!m_buffers_count)
{
return;
}
@@ -158,145 +158,160 @@ void VertexManager::PrepareVBuffers(int stride)
int TdataSize = IndexGenerator::GetTriangleindexLen();
int LDataSize = IndexGenerator::GetLineindexLen();
int PDataSize = IndexGenerator::GetPointindexLen();
int IndexDataSize = TdataSize + LDataSize + PDataSize;
int IndexDataSize = TdataSize + LDataSize;
DWORD LockMode = D3DLOCK_NOOVERWRITE;
if (CurrentVBufferIndex > CurrentVBufferSize - datasize)
m_vertex_buffer_cursor--;
m_vertex_buffer_cursor = m_vertex_buffer_cursor - (m_vertex_buffer_cursor % stride) + stride;
if (m_vertex_buffer_cursor > m_vertex_buffer_size - datasize)
{
LockMode = D3DLOCK_DISCARD;
CurrentVBufferIndex = 0;
CurrentVBuffer = (CurrentVBuffer + 1) % NumVBuffers;
}
if(FAILED(VBuffers[CurrentVBuffer]->Lock(CurrentVBufferIndex, datasize,(VOID**)(&pVertices), LockMode)))
m_vertex_buffer_cursor = 0;
m_current_vertex_buffer = (m_current_vertex_buffer + 1) % m_buffers_count;
}
if(FAILED(m_vertex_buffers[m_current_vertex_buffer]->Lock(m_vertex_buffer_cursor, datasize,(VOID**)(&pVertices), LockMode)))
{
DestroyDeviceObjects();
return;
}
memcpy(pVertices, LocalVBuffer, datasize);
VBuffers[CurrentVBuffer]->Unlock();
memcpy(pVertices, s_pBaseBufferPointer, datasize);
m_vertex_buffers[m_current_vertex_buffer]->Unlock();
LockMode = D3DLOCK_NOOVERWRITE;
if (CurrentIBufferIndex > CurrentIBufferSize - IndexDataSize)
if (m_index_buffer_cursor > m_index_buffer_size - IndexDataSize)
{
LockMode = D3DLOCK_DISCARD;
CurrentIBufferIndex = 0;
CurrentIBuffer = (CurrentIBuffer + 1) % NumVBuffers;
}
m_index_buffer_cursor = 0;
m_current_index_buffer = (m_current_index_buffer + 1) % m_buffers_count;
}
if(FAILED(IBuffers[CurrentIBuffer]->Lock(CurrentIBufferIndex * sizeof(u16), IndexDataSize * sizeof(u16), (VOID**)(&pIndices), LockMode )))
if(FAILED(m_index_buffers[m_current_index_buffer]->Lock(m_index_buffer_cursor * sizeof(u16), IndexDataSize * sizeof(u16), (VOID**)(&pIndices), LockMode )))
{
DestroyDeviceObjects();
return;
}
if(TdataSize)
{
memcpy(pIndices, TIBuffer, TdataSize * sizeof(u16));
memcpy(pIndices, GetTriangleIndexBuffer(), TdataSize * sizeof(u16));
pIndices += TdataSize;
}
if(LDataSize)
{
memcpy(pIndices, LIBuffer, LDataSize * sizeof(u16));
memcpy(pIndices, GetLineIndexBuffer(), LDataSize * sizeof(u16));
pIndices += LDataSize;
}
if(PDataSize)
{
memcpy(pIndices, PIBuffer, PDataSize * sizeof(u16));
}
IBuffers[CurrentIBuffer]->Unlock();
D3D::dev->SetStreamSource( 0, VBuffers[CurrentVBuffer], CurrentVBufferIndex, stride);
if(CurrentIBufferIndex == 0)
m_index_buffers[m_current_index_buffer]->Unlock();
if(m_current_stride != stride || m_vertex_buffer_cursor == 0)
{
D3D::dev->SetIndices(IBuffers[CurrentIBuffer]);
m_current_stride = stride;
D3D::SetStreamSource( 0, m_vertex_buffers[m_current_vertex_buffer], 0, stride);
}
}
void VertexManager::DrawVB(int stride)
{
if (IndexGenerator::GetNumTriangles() > 0)
if (m_index_buffer_cursor == 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
0,
0,
IndexGenerator::GetNumVerts(),
CurrentIBufferIndex,
IndexGenerator::GetNumTriangles())))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumLines() > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitive(
D3DPT_LINELIST,
0,
0,
IndexGenerator::GetNumVerts(),
CurrentIBufferIndex + IndexGenerator::GetTriangleindexLen(),
IndexGenerator::GetNumLines())))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumPoints() > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitive(
D3DPT_POINTLIST,
0,
0,
IndexGenerator::GetNumVerts(),
CurrentIBufferIndex + IndexGenerator::GetTriangleindexLen() + IndexGenerator::GetLineindexLen(),
IndexGenerator::GetNumPoints())))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::SetIndices(m_index_buffers[m_current_index_buffer]);
}
}
void VertexManager::DrawVA(int stride)
{
if (IndexGenerator::GetNumTriangles() > 0)
void VertexManager::DrawVertexBuffer(int stride)
{
int triangles = IndexGenerator::GetNumTriangles();
int lines = IndexGenerator::GetNumLines();
int points = IndexGenerator::GetNumPoints();
int numverts = IndexGenerator::GetNumVerts();
int StartIndex = m_index_buffer_cursor;
int basevertex = m_vertex_buffer_cursor / stride;
if (triangles > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
basevertex,
0,
numverts,
StartIndex,
triangles)))
{
DumpBadShaders();
}
StartIndex += IndexGenerator::GetTriangleindexLen();
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (lines > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitive(
D3DPT_LINELIST,
basevertex,
0,
numverts,
StartIndex,
IndexGenerator::GetNumLines())))
{
DumpBadShaders();
}
StartIndex += IndexGenerator::GetLineindexLen();
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (points > 0)
{
//DrawIndexedPrimitive does not support point list so we have to draw the points one by one
for (int i = 0; i < points; i++)
{
if (FAILED(D3D::dev->DrawPrimitive(
D3DPT_POINTLIST,
basevertex + GetPointIndexBuffer()[i],
1)))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numDrawCalls);
}
}
}
void VertexManager::DrawVertexArray(int stride)
{
int triangles = IndexGenerator::GetNumTriangles();
int lines = IndexGenerator::GetNumLines();
int points = IndexGenerator::GetNumPoints();
int numverts = IndexGenerator::GetNumVerts();
if (triangles > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
D3DPT_TRIANGLELIST,
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumTriangles(),
TIBuffer,
0, numverts, triangles,
GetTriangleIndexBuffer(),
D3DFMT_INDEX16,
LocalVBuffer,
s_pBaseBufferPointer,
stride)))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumLines() > 0)
if (lines > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
D3DPT_LINELIST,
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumLines(),
LIBuffer,
0, numverts, lines,
GetLineIndexBuffer(),
D3DFMT_INDEX16,
LocalVBuffer,
s_pBaseBufferPointer,
stride)))
{
DumpBadShaders();
}
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumPoints() > 0)
if (points > 0)
{
if (FAILED(D3D::dev->DrawIndexedPrimitiveUP(
D3DPT_POINTLIST,
0, IndexGenerator::GetNumVerts(), IndexGenerator::GetNumPoints(),
PIBuffer,
0, numverts, points,
GetPointIndexBuffer(),
D3DFMT_INDEX16,
LocalVBuffer,
s_pBaseBufferPointer,
stride)))
{
DumpBadShaders();
@@ -307,11 +322,6 @@ void VertexManager::DrawVA(int stride)
void VertexManager::vFlush()
{
if (LocalVBuffer == s_pCurBufferPointer) return;
if (Flushed) return;
Flushed = true;
VideoFifo_CheckEFBAccess();
u32 usedtextures = 0;
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevorders[i / 2].getEnable(i & 1))
@@ -333,8 +343,8 @@ void VertexManager::vFlush()
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),
tex.texMode1[i&3].max_lod >> 4,
(tex.texMode0[i&3].min_filter & 3),
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
tex.texImage1[i&3].image_type);
if (tentry)
@@ -350,7 +360,7 @@ void VertexManager::vFlush()
// set global constants
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants();
int stride = g_nativeVertexFmt->GetVertexStride();
u32 stride = g_nativeVertexFmt->GetVertexStride();
if (!PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
@@ -362,9 +372,16 @@ void VertexManager::vFlush()
goto shader_fail;
}
PrepareVBuffers(stride);
PrepareDrawBuffers(stride);
g_nativeVertexFmt->SetupVertexPointers();
if(NumVBuffers){ DrawVB(stride);} else { DrawVA(stride);}
if(m_buffers_count)
{
DrawVertexBuffer(stride);
}
else
{
DrawVertexArray(stride);
}
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
@@ -377,18 +394,24 @@ void VertexManager::vFlush()
}
// update alpha only
g_renderer->ApplyState(true);
if(NumVBuffers){ DrawVB(stride);} else { DrawVA(stride);}
if(m_buffers_count)
{
DrawVertexBuffer(stride);
}
else
{
DrawVertexArray(stride);
}
g_renderer->RestoreState();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
shader_fail:
if(NumVBuffers)
if(m_buffers_count)
{
CurrentIBufferIndex += IndexGenerator::GetTriangleindexLen() + IndexGenerator::GetLineindexLen() + IndexGenerator::GetPointindexLen();
CurrentVBufferIndex += IndexGenerator::GetNumVerts() * stride;
m_index_buffer_cursor += IndexGenerator::GetTriangleindexLen() + IndexGenerator::GetLineindexLen() + IndexGenerator::GetPointindexLen();
m_vertex_buffer_cursor += IndexGenerator::GetNumVerts() * stride;
}
ResetBuffer();
}
}
@@ -34,18 +34,19 @@ public:
void CreateDeviceObjects();
void DestroyDeviceObjects();
private:
u32 CurrentVBufferIndex;
u32 CurrentVBufferSize;
u32 CurrentIBufferIndex;
u32 CurrentIBufferSize;
u32 NumVBuffers;
u32 CurrentVBuffer;
u32 CurrentIBuffer;
LPDIRECT3DVERTEXBUFFER9 *VBuffers;
LPDIRECT3DINDEXBUFFER9 *IBuffers;
void PrepareVBuffers(int stride);
void DrawVB(int stride);
void DrawVA(int stride);
u32 m_vertex_buffer_cursor;
u32 m_vertex_buffer_size;
u32 m_index_buffer_cursor;
u32 m_index_buffer_size;
u32 m_buffers_count;
u32 m_current_vertex_buffer;
u32 m_current_stride;
u32 m_current_index_buffer;
LPDIRECT3DVERTEXBUFFER9 *m_vertex_buffers;
LPDIRECT3DINDEXBUFFER9 *m_index_buffers;
void PrepareDrawBuffers(u32 stride);
void DrawVertexBuffer(int stride);
void DrawVertexArray(int stride);
// temp
void vFlush();
};
@@ -13,8 +13,10 @@ class VideoBackend : public VideoBackendHardware
void Shutdown();
std::string GetName();
std::string GetDisplayName();
void Video_Prepare();
void Video_Cleanup();
void ShowConfig(void* parent);
+13 -2
View File
@@ -57,6 +57,7 @@
#include "ConfigManager.h"
#include "VideoBackend.h"
#include "PerfQueryBase.h"
namespace DX9
{
@@ -86,6 +87,11 @@ std::string VideoBackend::GetName()
return "Direct3D9";
}
std::string VideoBackend::GetDisplayName()
{
return "Direct3D9 (deprecated)";
}
void InitBackendInfo()
{
DX9::D3D::Init();
@@ -93,11 +99,10 @@ void InitBackendInfo()
const int maxConstants = (shaderModel < 3) ? 32 : ((shaderModel < 4) ? 224 : 65536);
g_Config.backend_info.APIType = shaderModel < 3 ? API_D3D9_SM20 :API_D3D9_SM30;
g_Config.backend_info.bUseRGBATextures = false;
g_Config.backend_info.bUseMinimalMipCount = true;
g_Config.backend_info.bSupports3DVision = true;
g_Config.backend_info.bSupportsDualSourceBlend = false;
g_Config.backend_info.bSupportsFormatReinterpretation = true;
g_Config.backend_info.bSupportsPixelLighting = C_PLIGHTS + 40 <= maxConstants && C_PMATERIALS + 4 <= maxConstants;
// adapters
@@ -171,6 +176,7 @@ void VideoBackend::Video_Prepare()
g_vertex_manager = new VertexManager;
g_renderer = new Renderer;
g_texture_cache = new TextureCache;
g_perf_query = new PerfQueryBase;
// VideoCommon
BPInit();
Fifo_Init();
@@ -190,6 +196,7 @@ void VideoBackend::Shutdown()
{
s_BackendInitialized = false;
// TODO: should be in Video_Cleanup
if (g_renderer)
{
s_efbAccessRequested = FALSE;
@@ -208,6 +215,7 @@ void VideoBackend::Shutdown()
// internal interfaces
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
delete g_perf_query;
delete g_texture_cache;
delete g_renderer;
delete g_vertex_manager;
@@ -217,4 +225,7 @@ void VideoBackend::Shutdown()
D3D::Shutdown();
}
void VideoBackend::Video_Cleanup() {
}
}
@@ -2,10 +2,14 @@ set(SRCS Src/FramebufferManager.cpp
Src/GLUtil.cpp
Src/main.cpp
Src/NativeVertexFormat.cpp
Src/PerfQuery.cpp
Src/PixelShaderCache.cpp
Src/PostProcessing.cpp
Src/ProgramShaderCache.cpp
Src/RasterFont.cpp
Src/Render.cpp
Src/SamplerCache.cpp
Src/StreamBuffer.cpp
Src/TextureCache.cpp
Src/TextureConverter.cpp
Src/VertexShaderCache.cpp
@@ -33,12 +37,6 @@ if(wxWidgets_FOUND)
set(LIBS ${LIBS} ${wxWidgets_LIBRARIES})
endif(wxWidgets_FOUND)
if(WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(LIBS ${LIBS} Cg CgGL)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
list(APPEND LIBS "${CMAKE_SOURCE_DIR}/Externals/Cg/Cg.framework")
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBS ${LIBS} clrun)
endif()
@@ -121,8 +121,8 @@
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -133,8 +133,8 @@
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -147,8 +147,8 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -161,8 +161,8 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -175,8 +175,8 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -189,8 +189,8 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opengl32.lib;cg.lib;cgGL.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;..\..\..\Externals\Cg64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>opengl32.lib;glu32.lib;glew64s.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\..\Externals\GLew;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<OutputFile>..\..\..\Binary\$(PlatformName)\Plugins\$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Lib />
@@ -200,10 +200,14 @@
<ClCompile Include="Src\GLUtil.cpp" />
<ClCompile Include="Src\main.cpp" />
<ClCompile Include="Src\NativeVertexFormat.cpp" />
<ClCompile Include="Src\PerfQuery.cpp" />
<ClCompile Include="Src\PixelShaderCache.cpp" />
<ClCompile Include="Src\PostProcessing.cpp" />
<ClCompile Include="Src\ProgramShaderCache.cpp" />
<ClCompile Include="Src\RasterFont.cpp" />
<ClCompile Include="Src\Render.cpp" />
<ClCompile Include="Src\SamplerCache.cpp" />
<ClCompile Include="Src\StreamBuffer.cpp" />
<ClCompile Include="Src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
@@ -222,15 +226,17 @@
<ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\GLUtil.h" />
<ClInclude Include="Src\main.h" />
<ClInclude Include="Src\PixelShaderCache.h" />
<ClInclude Include="Src\PerfQuery.h" />
<ClInclude Include="Src\PostProcessing.h" />
<ClInclude Include="Src\ProgramShaderCache.h" />
<ClInclude Include="Src\RasterFont.h" />
<ClInclude Include="Src\Render.h" />
<ClInclude Include="Src\SamplerCache.h" />
<ClInclude Include="Src\StreamBuffer.h" />
<ClInclude Include="Src\stdafx.h" />
<ClInclude Include="Src\TextureCache.h" />
<ClInclude Include="Src\TextureConverter.h" />
<ClInclude Include="Src\VertexManager.h" />
<ClInclude Include="Src\VertexShaderCache.h" />
<ClInclude Include="Src\VideoBackend.h" />
</ItemGroup>
<ItemGroup>
@@ -27,15 +27,24 @@
<ClCompile Include="Src\PostProcessing.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\ProgramShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\Render.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\StreamBuffer.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\TextureCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\VertexShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PerfQuery.cpp">
<Filter>Render</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\Globals.h" />
@@ -57,10 +66,10 @@
<ClInclude Include="Src\FramebufferManager.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PixelShaderCache.h">
<ClInclude Include="Src\PostProcessing.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PostProcessing.h">
<ClInclude Include="Src\ProgramShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\Render.h">
@@ -69,7 +78,7 @@
<ClInclude Include="Src\TextureCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\VertexShaderCache.h">
<ClInclude Include="Src\PerfQuery.h">
<Filter>Render</Filter>
</ClInclude>
</ItemGroup>
@@ -90,4 +99,4 @@
<UniqueIdentifier>{aaa16061-dca9-4155-be44-f77538e839fc}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>
@@ -17,6 +17,7 @@
#include "Globals.h"
#include "FramebufferManager.h"
#include "VertexShaderGen.h"
#include "TextureConverter.h"
#include "Render.h"
@@ -25,8 +26,6 @@
namespace OGL
{
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp. ugly.
int FramebufferManager::m_targetWidth;
int FramebufferManager::m_targetHeight;
int FramebufferManager::m_msaaSamples;
@@ -41,7 +40,7 @@ GLuint FramebufferManager::m_resolvedFramebuffer;
GLuint FramebufferManager::m_resolvedColorTexture;
GLuint FramebufferManager::m_resolvedDepthTexture;
GLuint FramebufferManager::m_xfbFramebuffer; // Only used in MSAA mode
GLuint FramebufferManager::m_xfbFramebuffer;
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
@@ -52,7 +51,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
m_resolvedColorTexture = 0;
m_resolvedDepthTexture = 0;
m_xfbFramebuffer = 0;
m_targetWidth = targetWidth;
m_targetHeight = targetHeight;
@@ -72,7 +71,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
// Create EFB target.
glGenFramebuffersEXT(1, &m_efbFramebuffer);
glGenFramebuffers(1, &m_efbFramebuffer);
if (m_msaaSamples <= 1)
{
@@ -83,20 +82,20 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
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, m_efbColor);
glTexImage2D(GL_TEXTURE_RECTANGLE, 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, m_efbDepth);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
// Bind target textures to the EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, m_efbColor, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, m_efbDepth, 0);
GL_REPORT_FBO_ERROR();
}
@@ -109,67 +108,67 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
// Create EFB target renderbuffers.
GLuint glObj[2];
glGenRenderbuffersEXT(2, glObj);
glGenRenderbuffers(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
glBindRenderbuffer(GL_RENDERBUFFER, m_efbColor);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
glBindRenderbuffer(GL_RENDERBUFFER, m_efbDepth);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, 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);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Bind target renderbuffers to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 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);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_efbColor);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_efbDepth);
GL_REPORT_FBO_ERROR();
// Create resolved targets for transferring multisampled EFB to texture.
glGenFramebuffersEXT(1, &m_resolvedFramebuffer);
glGenFramebuffers(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, m_resolvedColorTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE, 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, m_resolvedDepthTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
// Bind resolved textures to resolved framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, m_resolvedColorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, m_resolvedDepthTexture, 0);
GL_REPORT_FBO_ERROR();
// Return to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
}
// Create XFB framebuffer; targets will be created elsewhere.
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
glGenFramebuffers(1, &m_xfbFramebuffer);
// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
glViewport(0, 0, m_targetWidth, m_targetHeight);
glScissor(0, 0, m_targetWidth, m_targetHeight);
@@ -180,7 +179,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
FramebufferManager::~FramebufferManager()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLuint glObj[3];
@@ -189,7 +188,7 @@ FramebufferManager::~FramebufferManager()
glObj[0] = m_efbFramebuffer;
glObj[1] = m_resolvedFramebuffer;
glObj[2] = m_xfbFramebuffer;
glDeleteFramebuffersEXT(3, glObj);
glDeleteFramebuffers(3, glObj);
m_efbFramebuffer = 0;
m_xfbFramebuffer = 0;
@@ -204,7 +203,7 @@ FramebufferManager::~FramebufferManager()
if (m_msaaSamples <= 1)
glDeleteTextures(2, glObj);
else
glDeleteRenderbuffersEXT(2, glObj);
glDeleteRenderbuffers(2, glObj);
m_efbColor = 0;
m_efbDepth = 0;
}
@@ -224,16 +223,16 @@ GLuint FramebufferManager::GetEFBColorTexture(const EFBRectangle& 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(
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
glBlitFramebuffer(
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
return m_resolvedColorTexture;
}
@@ -254,16 +253,16 @@ GLuint FramebufferManager::GetEFBDepthTexture(const EFBRectangle& 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(
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_efbFramebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolvedFramebuffer);
glBlitFramebuffer(
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
targetRc.left, targetRc.top, targetRc.right, targetRc.bottom,
GL_DEPTH_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer);
return m_resolvedDepthTexture;
}
@@ -284,7 +283,7 @@ void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c
void FramebufferManager::SetFramebuffer(GLuint fb)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb != 0 ? fb : GetEFBFramebuffer());
glBindFramebuffer(GL_FRAMEBUFFER, fb != 0 ? fb : GetEFBFramebuffer());
}
// Apply AA if enabled
@@ -298,106 +297,60 @@ GLuint FramebufferManager::ResolveAndGetDepthTarget(const EFBRectangle &source_r
return GetEFBDepthTexture(source_rect);
}
XFBSource::~XFBSource()
{
glDeleteRenderbuffers(1, &renderbuf);
}
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
const MathUtil::Rectangle<float> &drawrc, int width, int height) const
{
// Texture map xfbSource->texture onto the main buffer
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
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();
glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuf);
glBlitFramebuffer(sourcerc.left, sourcerc.bottom, sourcerc.right, sourcerc.top,
drawrc.left, drawrc.bottom, drawrc.right, drawrc.top,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
GL_REPORT_ERRORD();
}
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
{
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture);
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, renderbuf);
}
void XFBSource::CopyEFB(float Gamma)
{
// Copy EFB data to XFB and restore render target again
glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer());
#if 0
if (m_msaaSamples <= 1)
#else
if (!s_bHaveFramebufferBlit)
#endif
{
// Just copy the EFB directly.
// Bind texture.
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuf);
GL_REPORT_FBO_ERROR();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferManager::GetEFBFramebuffer());
glBlitFramebuffer(
0, 0, texWidth, texHeight,
0, 0, texWidth, texHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, texWidth, texHeight, 0);
// Return to EFB.
FramebufferManager::SetFramebuffer(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::GetEFBFramebuffer());
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, FramebufferManager::GetXFBFramebuffer());
// 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::GetEFBFramebuffer());
}
}
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
{
GLuint texture;
GLuint renderbuf;
glGenTextures(1, &texture);
glGenRenderbuffers(1, &renderbuf);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, target_width, target_height);
#if 0// XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible.
if (m_msaaSamples > 1)
#else
if (s_bHaveFramebufferBlit)
#endif
{
// In MSAA mode, allocate the texture image here. In non-MSAA mode,
// the image will be allocated by glCopyTexImage2D (later).
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, target_width, target_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
return new XFBSource(texture);
return new XFBSource(renderbuf);
}
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)
@@ -57,15 +57,15 @@ namespace OGL {
struct XFBSource : public XFBSourceBase
{
XFBSource(GLuint tex) : texture(tex) {}
~XFBSource() { glDeleteTextures(1, &texture); }
XFBSource(GLuint rbuf) : renderbuf(rbuf) {}
~XFBSource();
void CopyEFB(float Gamma);
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
void Draw(const MathUtil::Rectangle<float> &sourcerc,
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
const GLuint texture;
const GLuint renderbuf;
};
class FramebufferManager : public FramebufferManagerBase
+19 -25
View File
@@ -51,10 +51,10 @@ void VideoBackend::UpdateFPSDisplay(const char *text)
}
void InitInterface()
{
#if defined(USE_EGL) && USE_EGL
#ifdef ANDROID
GLInterface = new cInterfaceBase;
#elif defined(USE_EGL) && USE_EGL
GLInterface = new cInterfaceEGL;
#elif defined(USE_WX) && USE_WX
GLInterface = new cInterfaceWX;
#elif defined(__APPLE__)
GLInterface = new cInterfaceAGL;
#elif defined(_WIN32)
@@ -70,14 +70,14 @@ GLuint OpenGL_CompileProgram ( const char* vertexShader, const char* fragmentSha
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
GLuint programID = glCreateProgram();
GLint Result = GL_FALSE;
char stringBuffer[1024];
GLsizei stringBufferUsage = 0;
// compile vertex shader
glShaderSource(vertexShaderID, 1, &vertexShader, NULL);
glCompileShader(vertexShaderID);
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
GLint Result = GL_FALSE;
char stringBuffer[1024];
GLsizei stringBufferUsage = 0;
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderInfoLog(vertexShaderID, 1024, &stringBufferUsage, stringBuffer);
if(Result && stringBufferUsage) {
@@ -157,32 +157,26 @@ void OpenGL_ReportARBProgramError()
bool OpenGL_ReportFBOError(const char *function, const char *file, int line)
{
#ifndef USE_GLES
unsigned int fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT)
unsigned int fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE)
{
const char *error = "-";
const char *error = "unknown error";
switch (fbo_status)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
error = "INCOMPLETE_ATTACHMENT_EXT";
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
error = "INCOMPLETE_ATTACHMENT";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
error = "INCOMPLETE_MISSING_ATTACHMENT_EXT";
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
error = "INCOMPLETE_MISSING_ATTACHMENT";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
error = "INCOMPLETE_DIMENSIONS_EXT";
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
error = "INCOMPLETE_DRAW_BUFFER";
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
error = "INCOMPLETE_FORMATS_EXT";
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
error = "INCOMPLETE_READ_BUFFER";
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";
case GL_FRAMEBUFFER_UNSUPPORTED:
error = "UNSUPPORTED";
break;
}
ERROR_LOG(VIDEO, "%s:%d: (%s) OpenGL FBO error - %s\n",
+10 -14
View File
@@ -63,26 +63,22 @@ bool OpenGL_ReportFBOError(const char *function, const char *file, int 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
__forceinline GLenum GL_REPORT_ERROR() { return GL_NO_ERROR; }
#define GL_REPORT_ERRORD() (void)GL_NO_ERROR
#define GL_REPORT_FBO_ERROR() (void)true
#define GL_REPORT_PROGRAM_ERROR() (void)0
#endif
#if defined __APPLE__ || defined __linux__ || defined _WIN32
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#define HAVE_CG 1
extern CGcontext g_cgcontext;
extern CGprofile g_cgvProf, g_cgfProf;
// this should be removed in future, but as long as glsl is unstable, we should really read this messages
#if defined(_DEBUG) || defined(DEBUGFAST)
#define DEBUG_GLSL 1
#else
#define DEBUG_GLSL 0
#endif
// XXX: Dual-source blending in OpenGL does not work correctly yet. To make it
// work, we may need to use glBindFragDataLocation. To use that, we need to
// use GLSL shaders across the whole pipeline. Yikes!
//#define USE_DUAL_SOURCE_BLEND
// TODO: should be removed if we use glsl a lot
#define DEBUG_GLSL
// Isn't defined if we aren't using GLEW 1.6
#ifndef GL_ONE_MINUS_SRC1_ALPHA
#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
#endif
#endif // _GLINIT_H_
@@ -17,56 +17,18 @@
#include "GLUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "MemoryUtil.h"
#include "ProgramShaderCache.h"
#include "VertexShaderGen.h"
#include "CPMemory.h"
#include "NativeVertexFormat.h"
#include "VertexManager.h"
#define COMPILED_CODE_SIZE 4096
// TODO: this guy is never initialized
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();
virtual void EnableComponents(u32 components);
};
namespace OGL
{
@@ -75,23 +37,14 @@ 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
glDeleteVertexArrays(1, &VAO);
}
inline GLuint VarToGL(VarType t)
@@ -104,183 +57,56 @@ inline GLuint VarToGL(VarType t)
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
s_prevcomponents = 0;
vertex_stride = _vtx_decl.stride;
using namespace Gen;
this->vtx_decl = _vtx_decl;
vertex_stride = vtx_decl.stride;
// 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);
if (vertex_stride & 3)
PanicAlert("Uneven vertex stride: %i", vertex_stride);
emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0);
VertexManager *vm = (OGL::VertexManager*)g_vertex_manager;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// the element buffer is bound directly to the vao, so we must it set for every vao
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->m_index_buffers);
glBindBuffer(GL_ARRAY_BUFFER, vm->m_vertex_buffers);
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() {
// 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]));
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, vtx_decl.stride, (u8*)NULL);
for (int i = 0; i < 3; i++) {
if (vtx_decl.num_normals > i) {
glEnableVertexAttribArray(SHADER_NORM0_ATTRIB+i);
glVertexAttribPointer(SHADER_NORM0_ATTRIB+i, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.normal_offset[i]);
}
}
for (int i = 0; i < 2; i++) {
if (vtx_decl.color_offset[i] != -1) {
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]));
}
glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB+i);
glVertexAttribPointer(SHADER_COLOR0_ATTRIB+i, 4, GL_UNSIGNED_BYTE, GL_TRUE, vtx_decl.stride, (u8*)NULL + vtx_decl.color_offset[i]);
}
}
for (int i = 0; i < 8; i++) {
if (vtx_decl.texcoord_offset[i] != -1) {
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]));
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB+i);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB+i, vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]),
GL_FALSE, vtx_decl.stride, (u8*)NULL + vtx_decl.texcoord_offset[i]);
}
}
if (vtx_decl.posmtx_offset != -1) {
glVertexAttribPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset));
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
glVertexAttribIPointer(SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, vtx_decl.stride, (u8*)NULL + vtx_decl.posmtx_offset);
}
#endif
vm->m_last_vao = VAO;
}
void GLVertexFormat::SetupVertexPointers() {
}
void GLVertexFormat::EnableComponents(u32 components)
{
if (s_prevcomponents != components)
{
VertexManager::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 ((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);
}
}
s_prevcomponents = components;
}
}
@@ -0,0 +1,133 @@
#include "RenderBase.h"
#include "GLUtil.h"
#include "PerfQuery.h"
namespace OGL
{
PerfQuery::PerfQuery()
: m_query_read_pos()
, m_query_count()
{
for (u32 i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
glGenQueries(1, &m_query_buffer[i].query_id);
ResetQuery();
}
PerfQuery::~PerfQuery()
{
for (u32 i = 0; i != ARRAYSIZE(m_query_buffer); ++i)
glDeleteQueries(1, &m_query_buffer[i].query_id);
}
void PerfQuery::EnableQuery(PerfQueryGroup type)
{
// Is this sane?
if (m_query_count > ARRAYSIZE(m_query_buffer) / 2)
WeakFlush();
if (ARRAYSIZE(m_query_buffer) == m_query_count)
{
FlushOne();
//ERROR_LOG(VIDEO, "flushed query buffer early!");
}
// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ARRAYSIZE(m_query_buffer)];
glBeginQuery(GL_SAMPLES_PASSED, entry.query_id);
entry.query_type = type;
++m_query_count;
}
}
void PerfQuery::DisableQuery(PerfQueryGroup type)
{
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
glEndQuery(GL_SAMPLES_PASSED);
}
}
bool PerfQuery::IsFlushed() const
{
return 0 == m_query_count;
}
void PerfQuery::FlushOne()
{
auto& entry = m_query_buffer[m_query_read_pos];
GLuint result = 0;
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result);
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
m_query_read_pos = (m_query_read_pos + 1) % ARRAYSIZE(m_query_buffer);
--m_query_count;
}
// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
{
while (!IsFlushed())
FlushOne();
}
void PerfQuery::WeakFlush()
{
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];
GLuint result = GL_FALSE;
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);
if (GL_TRUE == result)
{
FlushOne();
}
else
{
break;
}
}
}
void PerfQuery::ResetQuery()
{
m_query_count = 0;
std::fill_n(m_results, ARRAYSIZE(m_results), 0);
}
u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
u32 result = 0;
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
{
result = m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
{
result = m_results[PQG_ZCOMP];
}
else if (type == PQ_BLEND_INPUT)
{
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_EFB_COPY_CLOCKS)
{
result = m_results[PQG_EFB_COPY_CLOCKS];
}
return result / 4;
}
} // namespace
@@ -0,0 +1,46 @@
#ifndef _PERFQUERY_H_
#define _PERFQUERY_H_
#include "PerfQueryBase.h"
namespace OGL {
class PerfQuery : public PerfQueryBase
{
public:
PerfQuery();
~PerfQuery();
void EnableQuery(PerfQueryGroup type);
void DisableQuery(PerfQueryGroup type);
void ResetQuery();
u32 GetQueryResult(PerfQueryType type);
void FlushResults();
bool IsFlushed() const;
private:
struct ActiveQuery
{
GLuint query_id;
PerfQueryGroup query_type;
};
// when testing in SMS: 64 was too small, 128 was ok
static const u32 PERF_QUERY_BUFFER_SIZE = 512;
void WeakFlush();
// Only use when non-empty
void FlushOne();
// This contains gl query objects with unretrieved results.
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
u32 m_query_read_pos;
// TODO: sloppy
volatile u32 m_query_count;
volatile u32 m_results[PQG_NUM_MEMBERS];
};
} // namespace
#endif // _PERFQUERY_H_
@@ -27,344 +27,88 @@
#include "Common.h"
#include "Render.h"
#include "VertexShaderGen.h"
#include "PixelShaderCache.h"
#include "ProgramShaderCache.h"
#include "PixelShaderManager.h"
#include "OnScreenDisplay.h"
#include "StringUtil.h"
#include "FileUtil.h"
#include "Debugger.h"
namespace OGL
{
static int s_nMaxPixelInstructions;
static GLuint s_ColorMatrixProgram = 0;
static GLuint s_DepthMatrixProgram = 0;
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
PixelShaderUid PixelShaderCache::s_curuid;
bool PixelShaderCache::s_displayCompileAlert;
GLuint PixelShaderCache::CurrentShader;
bool PixelShaderCache::ShaderEnabled;
PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry = NULL;
PixelShaderUid PixelShaderCache::last_uid;
GLuint PixelShaderCache::GetDepthMatrixProgram()
void SetPSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
{
return s_DepthMatrixProgram;
}
GLuint PixelShaderCache::GetColorMatrixProgram()
{
return s_ColorMatrixProgram;
}
void PixelShaderCache::Init()
{
glEnable(GL_FRAGMENT_PROGRAM_ARB);
ShaderEnabled = true;
CurrentShader = 0;
last_entry = NULL;
GL_REPORT_ERRORD();
s_displayCompileAlert = true;
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, (GLint *)&s_nMaxPixelInstructions);
if(s_nMaxPixelInstructions == 0) // Some combination of drivers and hardware returns zero for some reason.
s_nMaxPixelInstructions = 4096;
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxPixelInstructions = 4096;
#if CG_VERSION_NUM == 2100
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
for (int a = 0; a < NUM_UNIFORMS; ++a)
{
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[2048];
sprintf(pmatrixprog, "!!ARBfp1.0"
"TEMP R0;\n"
"TEMP R1;\n"
"PARAM K0 = { 0.5, 0.5, 0.5, 0.5};\n"
"TEX R0, fragment.texcoord[0], texture[0], RECT;\n"
"MUL R0, R0, program.env[%d];\n"
"ADD R0, R0, K0;\n"
"FLR R0, R0;\n"
"MUL R0, R0, program.env[%d];\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+5,C_COLORMATRIX+6, C_COLORMATRIX, C_COLORMATRIX+1, C_COLORMATRIX+2, C_COLORMATRIX+3, 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\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
//16777215/16777216*256, 1/255, 256, 0
"PARAM K0 = { 255.99998474121, 0.003921568627451, 256.0, 0.0};\n"
"PARAM K1 = { 15.0, 0.066666666666, 0.0, 0.0};\n"
//sample the depth value
"TEX R2, fragment.texcoord[0], texture[0], RECT;\n"
//scale from [0*16777216..1*16777216] to
//[0*16777215..1*16777215], multiply by 256
"MUL R0, R2.x, K0.x;\n" // *16777215/16777216*256
//It is easy to get bad results due to low precision
//here, for example converting like this:
//MUL R0,R0,{ 65536, 256, 1, 16777216 }
//FRC R0,R0
//gives {?, 128/255, 254/255, ?} for depth value 254/255
//on some gpus
"FLR R0.x,R0;\n" //bits 31..24
"SUB R0.yzw,R0,R0.x;\n" //subtract bits 31..24 from rest
"MUL R0.yzw,R0,K0.z;\n" // *256
"FLR R0.y,R0;\n" //bits 23..16
"SUB R0.zw,R0,R0.y;\n" //subtract bits 23..16 from rest
"MUL R0.zw,R0,K0.z;\n" // *256
"FLR R0.z,R0;\n" //bits 15..8
"MOV R0.w,R0.x;\n" //duplicate bit 31..24
"MUL R0,R0,K0.y;\n" // /255
"MUL R0.w,R0,K1.x;\n" // *15
"FLR R0.w,R0;\n" //bits 31..28
"MUL R0.w,R0,K1.y;\n" // /15
"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;
}
}
void PixelShaderCache::Shutdown()
{
glDeleteProgramsARB(1, &s_ColorMatrixProgram);
s_ColorMatrixProgram = 0;
glDeleteProgramsARB(1, &s_DepthMatrixProgram);
s_DepthMatrixProgram = 0;
PSCache::iterator iter = PixelShaders.begin();
for (; iter != PixelShaders.end(); iter++)
iter->second.Destroy();
PixelShaders.clear();
}
FRAGMENTSHADER* PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
{
PixelShaderUid uid;
GetPixelShaderUid(uid, dstAlphaMode, API_OPENGL, components);
// Check if the shader is already set
if (last_entry)
{
if (uid == last_uid)
if (!strcmp(name, UniformNames[a]))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return &last_entry->shader;
if (tmp.shader.UniformLocations[a] == -1)
return;
else
{
glUniform4fv(tmp.shader.UniformLocations[a] + offset, count, f);
return;
}
}
}
last_uid = uid;
PSCache::iterator iter = PixelShaders.find(uid);
if (iter != PixelShaders.end())
{
PSCacheEntry &entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return &last_entry->shader;
}
// Make an entry in the table
PSCacheEntry& newentry = PixelShaders[uid];
last_entry = &newentry;
PixelShaderCode code;
GeneratePixelShaderCode(code, dstAlphaMode, API_OPENGL, components);
if (g_ActiveConfig.bEnableShaderDebugging)
{
newentry.shader.strprog = code.GetBuffer();
}
#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).c_str(), counter++);
SaveData(szTemp, code.GetBuffer()); /// XXX
}
#endif
if (!code.GetBuffer() || !CompilePixelShader(newentry.shader, code.GetBuffer())) {
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return NULL;
}
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return &last_entry->shader;
}
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=224,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);
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
file << pstrprogram;
file.close();
PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%d):\n%s",
szTemp,
g_cgfProf,
cgGetLastListing(g_cgcontext));
return false;
}
// handle warnings
if (cgGetError() != CG_NO_ERROR)
{
WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext));
WARN_LOG(VIDEO, "%s", 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, "%s", pstrprogram);
ERROR_LOG(VIDEO, "%s", pcompiledprog);
}
cgDestroyProgram(tempprog);
#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);
}
}
// Renderer functions
void Renderer::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);
float const f[4] = {f1, f2, f3, f4};
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
return;
}
for (unsigned int a = 0; a < 10; ++a)
{
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
{
unsigned int offset = const_number - PSVar_Loc[a].reg;
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
return;
}
}
}
void Renderer::SetPSConstant4fv(unsigned int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number, f);
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, 1);
return;
}
for (unsigned int a = 0; a < 10; ++a)
{
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
{
unsigned int offset = const_number - PSVar_Loc[a].reg;
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f);
return;
}
}
}
void Renderer::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
{
for (unsigned int i = 0; i < count; i++,f+=4)
glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, const_number + i, f);
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiPSConstant4fv(const_number, f, count);
return;
}
for (unsigned int a = 0; a < 10; ++a)
{
if (const_number >= PSVar_Loc[a].reg && const_number < (PSVar_Loc[a].reg + PSVar_Loc[a].size))
{
unsigned int offset = const_number - PSVar_Loc[a].reg;
SetPSConstant4fvByName(PSVar_Loc[a].name, offset, f, count);
return;
}
}
}
} // namespace OGL
@@ -1,90 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _PIXELSHADERCACHE_H_
#define _PIXELSHADERCACHE_H_
#include <map>
#include <string>
#include "BPMemory.h"
#include "PixelShaderGen.h"
namespace OGL
{
struct FRAGMENTSHADER
{
FRAGMENTSHADER() : glprogid(0) { }
void Destroy()
{
if (glprogid)
{
glDeleteProgramsARB(1, &glprogid);
glprogid = 0;
}
}
GLuint glprogid; // opengl program id
std::string strprog;
};
class PixelShaderCache
{
struct PSCacheEntry
{
FRAGMENTSHADER shader;
PSCacheEntry() {}
~PSCacheEntry() {}
void Destroy()
{
shader.Destroy();
}
};
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
static PSCache PixelShaders;
static PixelShaderUid s_curuid; // the current pixel shader uid (progressively changed as memory is written)
static bool s_displayCompileAlert;
static GLuint CurrentShader;
static PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
static bool ShaderEnabled;
public:
static void Init();
static void Shutdown();
static FRAGMENTSHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components);
static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram);
static GLuint GetColorMatrixProgram();
static GLuint GetDepthMatrixProgram();
static void SetCurrentShader(GLuint Shader);
static void DisableShader();
};
} // namespace OGL
#endif // _PIXELSHADERCACHE_H_
@@ -20,7 +20,8 @@
#include "VideoConfig.h"
#include "GLUtil.h"
#include "PostProcessing.h"
#include "PixelShaderCache.h"
#include "ProgramShaderCache.h"
#include "FramebufferManager.h"
namespace OGL
{
@@ -29,16 +30,72 @@ namespace PostProcessing
{
static std::string s_currentShader;
static FRAGMENTSHADER s_shader;
static SHADER s_shader;
static bool s_enable;
static u32 s_width;
static u32 s_height;
static GLuint s_fbo;
static GLuint s_texture;
static GLuint s_vao;
static GLuint s_vbo;
static GLuint s_uniform_resolution;
static char s_vertex_shader[] =
"in vec2 rawpos;\n"
"in vec2 tex0;\n"
"out vec2 uv0;\n"
"void main(void) {\n"
" gl_Position = vec4(rawpos,0,1);\n"
" uv0 = tex0;\n"
"}\n";
void Init()
{
s_currentShader = "";
s_enable = 0;
s_width = 0;
s_height = 0;
glGenFramebuffers(1, &s_fbo);
glGenTextures(1, &s_texture);
glBindTexture(GL_TEXTURE_2D, s_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); // disable mipmaps
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, s_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_texture, 0);
FramebufferManager::SetFramebuffer(0);
glGenBuffers(1, &s_vbo);
glBindBuffer(GL_ARRAY_BUFFER, s_vbo);
GLfloat vertices[] = {
-1.f, -1.f, 0.f, 0.f,
-1.f, 1.f, 0.f, 1.f,
1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenVertexArrays(1, &s_vao);
glBindVertexArray( s_vao );
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
}
void Shutdown()
{
s_shader.Destroy();
glDeleteFramebuffers(1, &s_vbo);
glDeleteTextures(1, &s_texture);
glDeleteBuffers(1, &s_vbo);
glDeleteVertexArrays(1, &s_vao);
}
void ReloadShader()
@@ -46,45 +103,83 @@ void ReloadShader()
s_currentShader = "";
}
bool ApplyShader()
void BindTargetFramebuffer ()
{
if (s_currentShader != File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt")
{
// Set immediately to prevent endless recompiles on failure.
if (!g_ActiveConfig.sPostProcessingShader.empty())
s_currentShader = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt";
else
s_currentShader.clear();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_enable ? s_fbo : 0);
}
s_shader.Destroy();
void BlitToScreen()
{
if(!s_enable) return;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, s_width, s_height);
glBindVertexArray(s_vao);
s_shader.Bind();
glUniform4f(s_uniform_resolution, (float)s_width, (float)s_height, 1.0f/(float)s_width, 1.0f/(float)s_height);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, s_texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
/* glBindFramebuffer(GL_READ_FRAMEBUFFER, s_fbo);
glBlitFramebuffer(rc.left, rc.bottom, rc.right, rc.top,
rc.left, rc.bottom, rc.right, rc.top,
GL_COLOR_BUFFER_BIT, GL_NEAREST);*/
}
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());
}
}
}
void Update ( u32 width, u32 height )
{
ApplyShader();
if (s_shader.glprogid != 0)
{
PixelShaderCache::SetCurrentShader(s_shader.glprogid);
return true;
if(s_enable && (width != s_width || height != s_height)) {
s_width = width;
s_height = height;
// alloc texture for framebuffer
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, s_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
}
else
{
PixelShaderCache::DisableShader();
return false;
}
void ApplyShader()
{
// shader didn't changed
if (s_currentShader == g_ActiveConfig.sPostProcessingShader) return;
s_currentShader = g_ActiveConfig.sPostProcessingShader;
s_enable = false;
s_shader.Destroy();
// shader disabled
if (g_ActiveConfig.sPostProcessingShader == "") return;
// so need to compile shader
// loading shader code
std::string code;
std::string path = File::GetUserPath(D_SHADERS_IDX) + g_ActiveConfig.sPostProcessingShader + ".txt";
if(!File::ReadFileToString(true, path.c_str(), code)) {
ERROR_LOG(VIDEO, "post-processing shader not found: %s", path.c_str());
return;
}
// and compile it
if (!ProgramShaderCache::CompileShader(s_shader, s_vertex_shader, code.c_str())) {
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
return;
}
// read uniform locations
s_uniform_resolution = glGetUniformLocation(s_shader.glprogid, "resolution");
// successful
s_enable = true;
}
} // namespace
@@ -30,9 +30,13 @@ namespace PostProcessing
void Init();
void Shutdown();
void BindTargetFramebuffer();
void BlitToScreen();
void Update(u32 width, u32 height);
void ReloadShader();
// Returns false if no shader was applied.
bool ApplyShader();
void ApplyShader();
} // namespace
@@ -0,0 +1,540 @@
// 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 "ProgramShaderCache.h"
#include "MathUtil.h"
#include "StreamBuffer.h"
#include "Debugger.h"
#include "Statistics.h"
#include "ImageWrite.h"
#include "Render.h"
namespace OGL
{
static const u32 UBO_LENGTH = 32*1024*1024;
GLintptr ProgramShaderCache::s_vs_data_size;
GLintptr ProgramShaderCache::s_ps_data_size;
GLintptr ProgramShaderCache::s_vs_data_offset;
u8 *ProgramShaderCache::s_ubo_buffer;
u32 ProgramShaderCache::s_ubo_buffer_size;
bool ProgramShaderCache::s_ubo_dirty;
static StreamBuffer *s_buffer;
LinearDiskCache<SHADERUID, u8> g_program_disk_cache;
static GLuint CurrentProgram = 0;
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
SHADERUID ProgramShaderCache::last_uid;
static char s_glsl_header[1024] = "";
const char *UniformNames[NUM_UNIFORMS] =
{
// PIXEL SHADER UNIFORMS
I_COLORS,
I_KCOLORS,
I_ALPHA,
I_TEXDIMS,
I_ZBIAS ,
I_INDTEXSCALE ,
I_INDTEXMTX,
I_FOG,
I_PLIGHTS,
I_PMATERIALS,
// VERTEX SHADER UNIFORMS
I_POSNORMALMATRIX,
I_PROJECTION ,
I_MATERIALS,
I_LIGHTS,
I_TEXMATRICES,
I_TRANSFORMMATRICES ,
I_NORMALMATRICES ,
I_POSTTRANSFORMMATRICES,
I_DEPTHPARAMS,
};
void SHADER::SetProgramVariables()
{
// glsl shader must be bind to set samplers
Bind();
// Bind UBO
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock");
GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock");
if(PSBlock_id != -1)
glUniformBlockBinding(glprogid, PSBlock_id, 1);
if(VSBlock_id != -1)
glUniformBlockBinding(glprogid, VSBlock_id, 2);
}
// We cache our uniform locations for now
// Once we move up to a newer version of GLSL, ~1.30
// We can remove this
// (Sonicadvance): For some reason this fails on my hardware
//glGetUniformIndices(glprogid, NUM_UNIFORMS, UniformNames, UniformLocations);
// Got to do it this crappy way.
UniformLocations[0] = glGetUniformLocation(glprogid, UniformNames[0]);
if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
for (int a = 1; a < NUM_UNIFORMS; ++a)
UniformLocations[a] = glGetUniformLocation(glprogid, UniformNames[a]);
// Bind Texture Sampler
for (int a = 0; a <= 9; ++a)
{
char name[8];
snprintf(name, 8, "samp%d", a);
// Still need to get sampler locations since we aren't binding them statically in the shaders
int loc = glGetUniformLocation(glprogid, name);
if (loc != -1)
glUniform1i(loc, a);
}
}
void SHADER::SetProgramBindings()
{
if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
{
// So we do support extended blending
// So we need to set a few more things here.
// Bind our out locations
glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0");
glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1");
}
else
glBindFragDataLocation(glprogid, 0, "ocol0");
// Need to set some attribute locations
glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos");
glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "fposmtx");
glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0");
glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1");
glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0");
glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1");
glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2");
for(int i=0; i<8; i++) {
char attrib_name[8];
snprintf(attrib_name, 8, "tex%d", i);
glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB+i, attrib_name);
}
}
void SHADER::Bind()
{
if(CurrentProgram != glprogid)
{
glUseProgram(glprogid);
CurrentProgram = glprogid;
}
}
void ProgramShaderCache::SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count)
{
s_ubo_dirty = true;
memcpy(s_ubo_buffer+(offset*4*sizeof(float)), f, count*4*sizeof(float));
}
void ProgramShaderCache::SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count)
{
s_ubo_dirty = true;
memcpy(s_ubo_buffer+(offset*4*sizeof(float))+s_vs_data_offset, f, count*4*sizeof(float));
}
void ProgramShaderCache::UploadConstants()
{
if(s_ubo_dirty) {
s_buffer->Alloc(s_ubo_buffer_size);
size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size);
glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_ps_data_size);
glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_vs_data_size);
s_ubo_dirty = false;
}
}
GLuint ProgramShaderCache::GetCurrentProgram(void)
{
return CurrentProgram;
}
SHADER* ProgramShaderCache::SetShader ( DSTALPHA_MODE dstAlphaMode, u32 components )
{
SHADERUID uid;
GetShaderId(&uid, dstAlphaMode, components);
// Check if the shader is already set
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
last_entry->shader.Bind();
return &last_entry->shader;
}
}
last_uid = uid;
// Check if shader is already in cache
PCache::iterator iter = pshaders.find(uid);
if (iter != pshaders.end())
{
PCacheEntry *entry = &iter->second;
last_entry = entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
last_entry->shader.Bind();
return &last_entry->shader;
}
// Make an entry in the table
PCacheEntry& newentry = pshaders[uid];
last_entry = &newentry;
newentry.in_cache = 0;
VertexShaderCode vcode;
PixelShaderCode pcode;
GenerateVertexShaderCode(vcode, components, API_OPENGL);
GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components);
if (g_ActiveConfig.bEnableShaderDebugging)
{
newentry.shader.strvprog = vcode.GetBuffer();
newentry.shader.strpprog = pcode.GetBuffer();
}
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_ActiveConfig.iLog & CONF_SAVESHADERS) {
static int counter = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
SaveData(szTemp, vcode.GetBuffer());
sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++);
SaveData(szTemp, pcode.GetBuffer());
}
#endif
if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer())) {
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return NULL;
}
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
last_entry->shader.Bind();
return &last_entry->shader;
}
bool ProgramShaderCache::CompileShader ( SHADER& shader, const char* vcode, const char* pcode )
{
GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode);
GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode);
if(!vsid || !psid)
{
glDeleteShader(vsid);
glDeleteShader(psid);
return false;
}
GLuint pid = shader.glprogid = glCreateProgram();;
glAttachShader(pid, vsid);
glAttachShader(pid, psid);
if (g_ogl_config.bSupportsGLSLCache)
glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
shader.SetProgramBindings();
glLinkProgram(pid);
// original shaders aren't needed any more
glDeleteShader(vsid);
glDeleteShader(psid);
GLint linkStatus;
glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus);
GLsizei length = 0;
glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length);
if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
{
GLsizei charsWritten;
GLchar* infoLog = new GLchar[length];
glGetProgramInfoLog(pid, length, &charsWritten, infoLog);
ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog);
char szTemp[MAX_PATH];
sprintf(szTemp, "%sp_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), pid);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << infoLog << s_glsl_header << vcode << s_glsl_header << pcode;
file.close();
delete [] infoLog;
}
if (linkStatus != GL_TRUE)
{
// Compile failed
ERROR_LOG(VIDEO, "Program linking failed; see info log");
// Don't try to use this shader
glDeleteProgram(pid);
return false;
}
shader.SetProgramVariables();
return true;
}
GLuint ProgramShaderCache::CompileSingleShader (GLuint type, const char* code )
{
GLuint result = glCreateShader(type);
const char *src[] = {s_glsl_header, code};
glShaderSource(result, 2, src, NULL);
glCompileShader(result);
GLint compileStatus;
glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus);
GLsizei length = 0;
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length);
if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL))
{
GLsizei charsWritten;
GLchar* infoLog = new GLchar[length];
glGetShaderInfoLog(result, length, &charsWritten, infoLog);
ERROR_LOG(VIDEO, "PS Shader info log:\n%s", infoLog);
char szTemp[MAX_PATH];
sprintf(szTemp, "%sps_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), result);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << infoLog << s_glsl_header << code;
file.close();
delete[] infoLog;
}
if (compileStatus != GL_TRUE)
{
// Compile failed
ERROR_LOG(VIDEO, "Shader compilation failed; see info log");
// Don't try to use this shader
glDeleteShader(result);
return 0;
}
(void)GL_REPORT_ERROR();
return result;
}
void ProgramShaderCache::GetShaderId ( SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components )
{
GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components);
GetVertexShaderUid(uid->vuid, components, API_OPENGL);
}
ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram(void)
{
return *last_entry;
}
void ProgramShaderCache::Init(void)
{
// We have to get the UBO alignment here because
// if we generate a buffer that isn't aligned
// then the UBO will fail.
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
GLint Align;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &Align);
s_ps_data_size = C_PENVCONST_END * sizeof(float) * 4;
s_vs_data_size = C_VENVCONST_END * sizeof(float) * 4;
s_vs_data_offset = ROUND_UP(s_ps_data_size, Align);
s_ubo_buffer_size = ROUND_UP(s_ps_data_size, Align) + ROUND_UP(s_vs_data_size, Align);
// We multiply by *4*4 because we need to get down to basic machine units.
// So multiply by four to get how many floats we have from vec4s
// Then once more to get bytes
s_buffer = new StreamBuffer(GL_UNIFORM_BUFFER, UBO_LENGTH);
s_ubo_buffer = new u8[s_ubo_buffer_size];
memset(s_ubo_buffer, 0, s_ubo_buffer_size);
s_ubo_dirty = true;
}
// Read our shader cache, only if supported
if (g_ogl_config.bSupportsGLSLCache)
{
GLint Supported;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
if(!Supported)
{
ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So disable shader cache.");
g_ogl_config.bSupportsGLSLCache = false;
}
else
{
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
char cache_filename[MAX_PATH];
sprintf(cache_filename, "%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
ProgramShaderCacheInserter inserter;
g_program_disk_cache.OpenAndRead(cache_filename, inserter);
}
SETSTAT(stats.numPixelShadersAlive, pshaders.size());
}
CreateHeader();
CurrentProgram = 0;
last_entry = NULL;
}
void ProgramShaderCache::Shutdown(void)
{
// store all shaders in cache on disk
if (g_ogl_config.bSupportsGLSLCache)
{
PCache::iterator iter = pshaders.begin();
for (; iter != pshaders.end(); ++iter)
{
if(iter->second.in_cache) continue;
GLint binary_size;
glGetProgramiv(iter->second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
if(!binary_size) continue;
u8 *data = new u8[binary_size+sizeof(GLenum)];
u8 *binary = data + sizeof(GLenum);
GLenum *prog_format = (GLenum*)data;
glGetProgramBinary(iter->second.shader.glprogid, binary_size, NULL, prog_format, binary);
g_program_disk_cache.Append(iter->first, data, binary_size+sizeof(GLenum));
delete [] data;
}
g_program_disk_cache.Sync();
g_program_disk_cache.Close();
}
glUseProgram(0);
PCache::iterator iter = pshaders.begin();
for (; iter != pshaders.end(); ++iter)
iter->second.Destroy();
pshaders.clear();
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
delete s_buffer;
s_buffer = 0;
delete [] s_ubo_buffer;
s_ubo_buffer = 0;
}
}
void ProgramShaderCache::CreateHeader ( void )
{
#ifdef _WIN32
// Intel Windows driver has a issue:
// their glsl doesn't know about the ubo extension, so we can't load it.
// but as version 140, ubo is in core and don't have to be loaded in glsl.
// as sandy do ogl3.1, glsl 140 is supported, so force it in this way.
// TODO: remove this again when the issue is fixed:
// see http://communities.intel.com/thread/36084
bool glsl140_hack = strcmp(g_ogl_config.gl_vendor, "Intel") == 0;
#elif __APPLE__
// as apple doesn't support glsl130 at all, we also have to use glsl140
bool glsl140_hack = true;
#else
bool glsl140_hack = false;
#endif
snprintf(s_glsl_header, sizeof(s_glsl_header),
"#version %s\n"
"%s\n" // tex_rect
"%s\n" // ubo
"\n"// A few required defines and ones that will make our lives a lot easier
"#define ATTRIN in\n"
"#define ATTROUT out\n"
"#define VARYIN centroid in\n"
"#define VARYOUT centroid out\n"
// Silly differences
"#define float2 vec2\n"
"#define float3 vec3\n"
"#define float4 vec4\n"
// hlsl to glsl function translation
"#define frac(x) fract(x)\n"
"#define saturate(x) clamp(x, 0.0f, 1.0f)\n"
"#define lerp(x, y, z) mix(x, y, z)\n"
, glsl140_hack ? "140" : "130"
, glsl140_hack ? "#define texture2DRect texture" : "#extension GL_ARB_texture_rectangle : enable"
, g_ActiveConfig.backend_info.bSupportsGLSLUBO && !glsl140_hack ? "#extension GL_ARB_uniform_buffer_object : enable" : "// ubo disabled"
);
}
void ProgramShaderCache::ProgramShaderCacheInserter::Read ( const SHADERUID& key, const u8* value, u32 value_size )
{
const u8 *binary = value+sizeof(GLenum);
GLenum *prog_format = (GLenum*)value;
GLint binary_size = value_size-sizeof(GLenum);
PCacheEntry entry;
entry.in_cache = 1;
entry.shader.glprogid = glCreateProgram();
glProgramBinary(entry.shader.glprogid, *prog_format, binary, binary_size);
GLint success;
glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success);
if (success)
{
pshaders[key] = entry;
entry.shader.SetProgramVariables();
}
else
glDeleteProgram(entry.shader.glprogid);
}
} // namespace OGL
@@ -0,0 +1,131 @@
// 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 PROGRAM_SHADER_CACHE_H_
#define PROGRAM_SHADER_CACHE_H_
#include "GLUtil.h"
#include "PixelShaderGen.h"
#include "VertexShaderGen.h"
#include "LinearDiskCache.h"
#include "ConfigManager.h"
namespace OGL
{
class SHADERUID
{
public:
VertexShaderUid vuid;
PixelShaderUid puid;
SHADERUID() {}
SHADERUID(const SHADERUID& r) : vuid(r.vuid), puid(r.puid) {}
bool operator <(const SHADERUID& r) const
{
if(puid < r.puid) return true;
if(r.puid < puid) return false;
if(vuid < r.vuid) return true;
return false;
}
bool operator ==(const SHADERUID& r) const
{
return puid == r.puid && vuid == r.vuid;
}
};
const int NUM_UNIFORMS = 19;
extern const char *UniformNames[NUM_UNIFORMS];
struct SHADER
{
SHADER() : glprogid(0) { }
void Destroy()
{
glDeleteProgram(glprogid);
glprogid = 0;
}
GLuint glprogid; // opengl program id
std::string strvprog, strpprog;
GLint UniformLocations[NUM_UNIFORMS];
void SetProgramVariables();
void SetProgramBindings();
void Bind();
};
class ProgramShaderCache
{
public:
struct PCacheEntry
{
SHADER shader;
bool in_cache;
void Destroy()
{
shader.Destroy();
}
};
static PCacheEntry GetShaderProgram(void);
static GLuint GetCurrentProgram(void);
static SHADER* SetShader(DSTALPHA_MODE dstAlphaMode, u32 components);
static void GetShaderId(SHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 components);
static bool CompileShader(SHADER &shader, const char* vcode, const char* pcode);
static GLuint CompileSingleShader(GLuint type, const char *code);
static void SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count);
static void SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count);
static void UploadConstants();
static void Init(void);
static void Shutdown(void);
static void CreateHeader(void);
private:
class ProgramShaderCacheInserter : public LinearDiskCacheReader<SHADERUID, u8>
{
public:
void Read(const SHADERUID &key, const u8 *value, u32 value_size);
};
typedef std::map<SHADERUID, PCacheEntry> PCache;
static PCache pshaders;
static PCacheEntry* last_entry;
static SHADERUID last_uid;
static GLintptr s_vs_data_size;
static GLintptr s_ps_data_size;
static GLintptr s_vs_data_offset;
static u8 *s_ubo_buffer;
static u32 s_ubo_buffer_size;
static bool s_ubo_dirty;
};
} // namespace OGL
#endif
+149 -88
View File
@@ -17,12 +17,18 @@
#include "GLUtil.h"
#include <string.h>
#include "RasterFont.h"
#include "ProgramShaderCache.h"
// globals
const GLubyte rasters[][13] = {
namespace OGL {
static const u32 char_width = 8;
static const u32 char_height = 13;
static const u32 char_offset = 32;
static const u32 char_count = 95;
const u8 rasters[char_count][char_height] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
@@ -120,104 +126,159 @@ const GLubyte rasters[][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
};
static const char *s_vertexShaderSrc =
"uniform vec2 charSize;\n"
"in vec2 rawpos;\n"
"in vec2 tex0;\n"
"out vec2 uv0;\n"
"void main(void) {\n"
" gl_Position = vec4(rawpos,0,1);\n"
" uv0 = tex0 * charSize;\n"
"}\n";
static const char *s_fragmentShaderSrc =
"uniform sampler2D samp8;\n"
"uniform vec4 color;\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"void main(void) {\n"
" ocol0 = texture(samp8,uv0) * color;\n"
"}\n";
static SHADER s_shader;
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();
// generate the texture
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0+8);
glBindTexture(GL_TEXTURE_2D, texture);
u32* texture_data = new u32[char_width*char_count*char_height];
for(u32 y=0; y<char_height; y++) {
for(u32 c=0; c<char_count; c++) {
for(u32 x=0; x<char_width; x++) {
bool pixel = rasters[c][y] & (1<<(char_width-x-1));
texture_data[char_width*char_count*y+char_width*c+x] = pixel ? -1 : 0;
}
}
}
temp_buffer = new char[TEMP_BUFFER_SIZE];
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, char_width*char_count, char_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
delete [] texture_data;
// generate shader
ProgramShaderCache::CompileShader(s_shader, s_vertexShaderSrc, s_fragmentShaderSrc);
// bound uniforms
glUniform2f(glGetUniformLocation(s_shader.glprogid,"charSize"), 1.0f / GLfloat(char_count), 1.0f);
uniform_color_id = glGetUniformLocation(s_shader.glprogid,"color");
glUniform4f(uniform_color_id, 1.0f, 1.0f, 1.0f, 1.0f);
cached_color = -1;
// generate VBO & VAO
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, NULL);
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
}
RasterFont::~RasterFont()
{
glDeleteLists(fontOffset, 128);
delete [] temp_buffer;
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
s_shader.Destroy();
}
void RasterFont::printString(const char *s, double x, double y, double z)
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight, u32 color)
{
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;
size_t length = strlen(text);
GLfloat *vertices = new GLfloat[length*6*4];
int usage = 0;
GLfloat delta_x = GLfloat(2*char_width)/GLfloat(bbWidth);
GLfloat delta_y = GLfloat(2*char_height)/GLfloat(bbHeight);
GLfloat border_x = 2.0/GLfloat(bbWidth);
GLfloat border_y = 4.0/GLfloat(bbHeight);
GLfloat x = GLfloat(start_x);
GLfloat y = GLfloat(start_y);
for(size_t i=0; i<length; i++) {
u8 c = text[i];
if(c == '\n') {
x = start_x;
t = temp;
y -= delta_y + border_y;
continue;
}
else if (*text == '\r')
{
t = temp;
// do not print spaces, they can be skipped easyly
if(c == ' ') {
x += delta_x + border_x;
continue;
}
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(c < char_offset || c >= char_count+char_offset) continue;
vertices[usage++] = x;
vertices[usage++] = y;
vertices[usage++] = GLfloat(c-char_offset);
vertices[usage++] = 0.0f;
vertices[usage++] = x+delta_x;
vertices[usage++] = y;
vertices[usage++] = GLfloat(c-char_offset+1);
vertices[usage++] = 0.0f;
vertices[usage++] = x+delta_x;
vertices[usage++] = y+delta_y;
vertices[usage++] = GLfloat(c-char_offset+1);
vertices[usage++] = 1.0f;
vertices[usage++] = x;
vertices[usage++] = y;
vertices[usage++] = GLfloat(c-char_offset);
vertices[usage++] = 0.0f;
vertices[usage++] = x+delta_x;
vertices[usage++] = y+delta_y;
vertices[usage++] = GLfloat(c-char_offset+1);
vertices[usage++] = 1.0f;
vertices[usage++] = x;
vertices[usage++] = y+delta_y;
vertices[usage++] = GLfloat(c-char_offset);
vertices[usage++] = 1.0f;
x += delta_x + border_x;
}
// ????
if (t != text)
{
*t = 0;
printString(temp, x, y, z);
if(!usage) {
delete [] vertices;
return;
}
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, usage*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
delete [] vertices;
s_shader.Bind();
if(color != cached_color) {
glUniform4f(uniform_color_id, GLfloat((color>>16)&0xff)/255.f,GLfloat((color>>8)&0xff)/255.f,GLfloat((color>>0)&0xff)/255.f,GLfloat((color>>24)&0xff)/255.f);
cached_color = color;
}
glActiveTexture(GL_TEXTURE0+8);
glDrawArrays(GL_TRIANGLES, 0, usage/4);
}
}
+11 -12
View File
@@ -18,25 +18,24 @@
#ifndef _RASTERFONT_H_
#define _RASTERFONT_H_
namespace OGL {
class RasterFont {
public:
RasterFont();
~RasterFont(void);
static int debug;
// some useful constants
enum {char_width = 10};
enum {char_height = 15};
// and the happy helper functions
void printString(const char *s, double x, double y, double z=0.0);
void printCenteredString(const char *s, double y, int screen_width, double z=0.0);
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight);
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight, u32 color);
private:
int fontOffset;
char *temp_buffer;
enum {TEMP_BUFFER_SIZE = 64 * 1024};
u32 VBO;
u32 VAO;
u32 texture;
u32 uniform_color_id;
u32 cached_color;
};
}
#endif // _RASTERFONT_H_
File diff suppressed because it is too large Load Diff
@@ -9,11 +9,30 @@ namespace OGL
void ClearEFBCache();
// ogl-only config, so not in VideoConfig.h
extern struct VideoConfig {
bool bSupportsGLSLCache;
bool bSupportsGLPinnedMemory;
bool bSupportsGLSync;
bool bSupportsGLBaseVertex;
bool bSupportCoverageMSAA;
bool bSupportSampleShading;
const char *gl_vendor;
const char *gl_renderer;
const char* gl_version;
s32 max_samples;
} g_ogl_config;
class Renderer : public ::Renderer
{
public:
Renderer();
~Renderer();
static void Init();
static void Shutdown();
void SetColorMask();
void SetBlendMode(bool forceUpdate);
@@ -0,0 +1,129 @@
// 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 "SamplerCache.h"
namespace OGL
{
SamplerCache *g_sampler_cache;
SamplerCache::SamplerCache()
: m_last_max_anisotropy()
{}
SamplerCache::~SamplerCache()
{
Clear();
}
void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1)
{
// TODO: can this go somewhere else?
if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy)
{
m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy;
Clear();
}
Params params(tm0, tm1);
// take equivalent forced linear when bForceFiltering
if (g_ActiveConfig.bForceFiltering)
{
params.tm0.min_filter |= 0x4;
params.tm0.mag_filter |= 0x1;
}
// TODO: Should keep a circular buffer for each stage of recently used samplers.
auto& active_sampler = m_active_samplers[stage];
if (active_sampler.first != params || !active_sampler.second.sampler_id)
{
// Active sampler does not match parameters (or is invalid), bind the proper one.
active_sampler.first = params;
active_sampler.second = GetEntry(params);
glBindSampler(stage, active_sampler.second.sampler_id);
}
}
auto SamplerCache::GetEntry(const Params& params) -> Value&
{
auto& val = m_cache[params];
if (!val.sampler_id)
{
// Sampler not found in cache, create it.
glGenSamplers(1, &val.sampler_id);
SetParameters(val.sampler_id, params);
// TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though.
//ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size());
}
return val;
}
void SamplerCache::SetParameters(GLuint sampler_id, const Params& params)
{
static const GLint min_filters[8] =
{
GL_NEAREST,
GL_NEAREST_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_NEAREST,
GL_LINEAR,
GL_LINEAR_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_LINEAR,
GL_LINEAR,
};
static const GLint wrap_settings[4] =
{
GL_CLAMP_TO_EDGE,
GL_REPEAT,
GL_MIRRORED_REPEAT,
GL_REPEAT,
};
auto& tm0 = params.tm0;
auto& tm1 = params.tm1;
glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filters[tm0.min_filter % ARRAYSIZE(min_filters)]);
glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, tm0.mag_filter ? GL_LINEAR : GL_NEAREST);
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]);
glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]);
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, tm0.lod_bias / 32.f);
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f);
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f);
if (g_ActiveConfig.iMaxAnisotropy > 0)
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << g_ActiveConfig.iMaxAnisotropy));
}
void SamplerCache::Clear()
{
for (auto it = m_cache.begin(); it != m_cache.end(); ++it)
{
glDeleteSamplers(1, &it->second.sampler_id);
}
m_cache.clear();
}
}
@@ -0,0 +1,80 @@
#ifndef INCLUDE_SAMPLER_CACHE_H_
#define INCLUDE_SAMPLER_CACHE_H_
#include <map>
#include "Render.h"
#include "GLUtil.h"
namespace OGL
{
class SamplerCache : NonCopyable
{
public:
SamplerCache();
~SamplerCache();
void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1);
void Clear();
private:
struct Params
{
union
{
struct
{
TexMode0 tm0;
TexMode1 tm1;
};
u64 hex;
};
Params()
: hex()
{}
Params(const TexMode0& _tm0, const TexMode1& _tm1)
: tm0(_tm0)
, tm1(_tm1)
{
static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int.");
}
bool operator<(const Params& other) const
{
return hex < other.hex;
}
bool operator!=(const Params& other) const
{
return hex != other.hex;
}
};
struct Value
{
Value()
: sampler_id()
{}
GLuint sampler_id;
};
void SetParameters(GLuint sampler_id, const Params& params);
Value& GetEntry(const Params& params);
std::map<Params, Value> m_cache;
std::pair<Params, Value> m_active_samplers[8];
int m_last_max_anisotropy;
};
extern SamplerCache *g_sampler_cache;
}
#endif
@@ -0,0 +1,242 @@
// 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 "Globals.h"
#include "GLUtil.h"
#include "StreamBuffer.h"
#include "MemoryUtil.h"
#include "Render.h"
namespace OGL
{
static const u32 SYNC_POINTS = 16;
static const u32 ALIGN_PINNED_MEMORY = 4096;
StreamBuffer::StreamBuffer(u32 type, size_t size, StreamType uploadType)
: m_uploadtype(uploadType), m_buffertype(type), m_size(size)
{
glGenBuffers(1, &m_buffer);
bool nvidia = !strcmp(g_ogl_config.gl_vendor, "NVIDIA Corporation");
if(m_uploadtype & STREAM_DETECT)
{
if(!g_ogl_config.bSupportsGLBaseVertex && (m_uploadtype & BUFFERSUBDATA))
m_uploadtype = BUFFERSUBDATA;
else if(g_ogl_config.bSupportsGLSync && g_Config.bHackedBufferUpload && (m_uploadtype & MAP_AND_RISK))
m_uploadtype = MAP_AND_RISK;
else if(g_ogl_config.bSupportsGLSync && g_ogl_config.bSupportsGLPinnedMemory && (m_uploadtype & PINNED_MEMORY))
m_uploadtype = PINNED_MEMORY;
else if(nvidia && (m_uploadtype & BUFFERSUBDATA))
m_uploadtype = BUFFERSUBDATA;
else if(g_ogl_config.bSupportsGLSync && (m_uploadtype & MAP_AND_SYNC))
m_uploadtype = MAP_AND_SYNC;
else
m_uploadtype = MAP_AND_ORPHAN;
}
Init();
}
StreamBuffer::~StreamBuffer()
{
Shutdown();
glDeleteBuffers(1, &m_buffer);
}
#define SLOT(x) (x)*SYNC_POINTS/m_size
void StreamBuffer::Alloc ( size_t size, u32 stride )
{
size_t m_iterator_aligned = m_iterator;
if(m_iterator_aligned && stride) {
m_iterator_aligned--;
m_iterator_aligned = m_iterator_aligned - (m_iterator_aligned % stride) + stride;
}
size_t iter_end = m_iterator_aligned + size;
switch(m_uploadtype) {
case MAP_AND_ORPHAN:
if(iter_end >= m_size) {
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
m_iterator_aligned = 0;
}
break;
case MAP_AND_SYNC:
case PINNED_MEMORY:
// insert waiting slots for used memory
for(u32 i=SLOT(m_used_iterator); i<SLOT(m_iterator); i++)
{
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
m_used_iterator = m_iterator;
// wait for new slots to end of buffer
for(u32 i=SLOT(m_free_iterator)+1; i<=SLOT(iter_end) && i < SYNC_POINTS; i++)
{
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(fences[i]);
}
m_free_iterator = iter_end;
// if buffer is full
if(iter_end >= m_size) {
// insert waiting slots in unused space at the end of the buffer
for(u32 i=SLOT(m_used_iterator); i < SYNC_POINTS; i++)
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// move to the start
m_used_iterator = m_iterator_aligned = m_iterator = 0; // offset 0 is always aligned
iter_end = size;
// wait for space at the start
for(u32 i=0; i<=SLOT(iter_end); i++)
{
glClientWaitSync(fences[i], GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(fences[i]);
}
m_free_iterator = iter_end;
}
break;
case MAP_AND_RISK:
if(iter_end >= m_size) {
m_iterator_aligned = 0;
}
break;
case BUFFERSUBDATA:
m_iterator_aligned = 0;
break;
case STREAM_DETECT:
case DETECT_MASK: // Just to shutup warnings
break;
}
m_iterator = m_iterator_aligned;
}
size_t StreamBuffer::Upload ( u8* data, size_t size )
{
switch(m_uploadtype) {
case MAP_AND_SYNC:
case MAP_AND_ORPHAN:
pointer = (u8*)glMapBufferRange(m_buffertype, m_iterator, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
if(pointer) {
memcpy(pointer, data, size);
glUnmapBuffer(m_buffertype);
} else {
ERROR_LOG(VIDEO, "buffer mapping failed");
}
break;
case PINNED_MEMORY:
case MAP_AND_RISK:
if(pointer)
memcpy(pointer+m_iterator, data, size);
break;
case BUFFERSUBDATA:
glBufferSubData(m_buffertype, m_iterator, size, data);
break;
case STREAM_DETECT:
case DETECT_MASK: // Just to shutup warnings
break;
}
size_t ret = m_iterator;
m_iterator += size;
return ret;
}
void StreamBuffer::Init()
{
m_iterator = 0;
m_used_iterator = 0;
m_free_iterator = 0;
switch(m_uploadtype) {
case MAP_AND_SYNC:
fences = new GLsync[SYNC_POINTS];
for(u32 i=0; i<SYNC_POINTS; i++)
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
case MAP_AND_ORPHAN:
case BUFFERSUBDATA:
glBindBuffer(m_buffertype, m_buffer);
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
break;
case PINNED_MEMORY:
glGetError(); // errors before this allocation should be ignored
fences = new GLsync[SYNC_POINTS];
for(u32 i=0; i<SYNC_POINTS; i++)
fences[i] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
pointer = (u8*)AllocateAlignedMemory(ROUND_UP(m_size,ALIGN_PINNED_MEMORY), ALIGN_PINNED_MEMORY );
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_buffer);
glBufferData(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, ROUND_UP(m_size,ALIGN_PINNED_MEMORY), pointer, GL_STREAM_COPY);
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
glBindBuffer(m_buffertype, m_buffer);
// on error, switch to another backend. some old catalyst seems to have broken pinned memory support
if(glGetError() != GL_NO_ERROR) {
ERROR_LOG(VIDEO, "pinned memory detected, but not working. Please report this: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version);
Shutdown();
m_uploadtype = MAP_AND_SYNC;
Init();
}
break;
case MAP_AND_RISK:
glBindBuffer(m_buffertype, m_buffer);
glBufferData(m_buffertype, m_size, NULL, GL_STREAM_DRAW);
pointer = (u8*)glMapBuffer(m_buffertype, GL_WRITE_ONLY);
glUnmapBuffer(m_buffertype);
if(!pointer)
ERROR_LOG(VIDEO, "buffer allocation failed");
case STREAM_DETECT:
case DETECT_MASK: // Just to shutup warnings
break;
}
}
void StreamBuffer::Shutdown()
{
switch(m_uploadtype) {
case MAP_AND_SYNC:
for(u32 i=0; i<SYNC_POINTS; i++)
glDeleteSync(fences[i]);
delete [] fences;
break;
case MAP_AND_RISK:
case MAP_AND_ORPHAN:
case BUFFERSUBDATA:
break;
case PINNED_MEMORY:
for(u32 i=0; i<SYNC_POINTS; i++)
glDeleteSync(fences[i]);
delete [] fences;
glBindBuffer(m_buffertype, 0);
glFinish(); // ogl pipeline must be flushed, else this buffer can be in use
FreeAlignedMemory(pointer);
break;
case STREAM_DETECT:
case DETECT_MASK: // Just to shutup warnings
break;
}
}
}
@@ -0,0 +1,72 @@
// 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 STREAMBUFFER_H
#define STREAMBUFFER_H
#include "VideoCommon.h"
#include "FramebufferManager.h"
#include "GLUtil.h"
// glew < 1.8 doesn't support pinned memory
#ifndef GLEW_AMD_pinned_memory
#define GLEW_AMD_pinned_memory glewIsSupported("GL_AMD_pinned_memory")
#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
#endif
namespace OGL
{
enum StreamType {
DETECT_MASK = 0x1F,
STREAM_DETECT = (1 << 0),
MAP_AND_ORPHAN = (1 << 1),
MAP_AND_SYNC = (1 << 2),
MAP_AND_RISK = (1 << 3),
PINNED_MEMORY = (1 << 4),
BUFFERSUBDATA = (1 << 5)
};
class StreamBuffer {
public:
StreamBuffer(u32 type, size_t size, StreamType uploadType = DETECT_MASK);
~StreamBuffer();
void Alloc(size_t size, u32 stride = 0);
size_t Upload(u8 *data, size_t size);
u32 getBuffer() { return m_buffer; }
private:
void Init();
void Shutdown();
StreamType m_uploadtype;
u32 m_buffer;
u32 m_buffertype;
size_t m_size;
u8 *pointer;
size_t m_iterator;
size_t m_used_iterator;
size_t m_free_iterator;
GLsync *fences;
};
}
#endif // STREAMBUFFER_H
@@ -42,7 +42,7 @@
#include "HW/Memmap.h"
#include "ImageWrite.h"
#include "MemoryUtil.h"
#include "PixelShaderCache.h"
#include "ProgramShaderCache.h"
#include "PixelShaderManager.h"
#include "Render.h"
#include "Statistics.h"
@@ -56,33 +56,36 @@
namespace OGL
{
static SHADER s_ColorMatrixProgram;
static SHADER s_DepthMatrixProgram;
static GLuint s_ColorMatrixUniform;
static GLuint s_DepthMatrixUniform;
static u32 s_ColorCbufid;
static u32 s_DepthCbufid;
static u32 s_Textures[8];
static u32 s_ActiveTexture;
static u32 s_NextStage;
struct VBOCache {
GLuint vbo;
GLuint vao;
TargetRectangle targetSource;
};
static std::map<u64,VBOCache> s_VBO;
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,
};
bool SaveTexture(const char* filename, u32 textarget, u32 tex, int virtual_width, int virtual_height, unsigned int level)
{
int width = std::max(virtual_width >> level, 1);
int height = std::max(virtual_height >> level, 1);
std::vector<u32> data(width * height);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(textarget, tex);
glGetTexImage(textarget, level, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
glBindTexture(textarget, 0);
TextureCache::SetStage();
const GLenum err = GL_REPORT_ERROR();
if (GL_NO_ERROR != err)
@@ -98,6 +101,9 @@ TextureCache::TCacheEntry::~TCacheEntry()
{
if (texture)
{
for(int i=0; i<8; i++)
if(s_Textures[i] == texture)
s_Textures[i] = 0;
glDeleteTextures(1, &texture);
texture = 0;
}
@@ -111,14 +117,17 @@ TextureCache::TCacheEntry::TCacheEntry()
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
GL_REPORT_ERRORD();
// TODO: is this already done somewhere else?
TexMode0 &tm0 = bpmem.tex[stage >> 2].texMode0[stage & 3];
TexMode1 &tm1 = bpmem.tex[stage >> 2].texMode1[stage & 3];
SetTextureParameters(tm0, tm1);
if (s_Textures[stage] != texture)
{
if (s_ActiveTexture != stage)
{
glActiveTexture(GL_TEXTURE0 + stage);
s_ActiveTexture = stage;
}
glBindTexture(GL_TEXTURE_2D, texture);
s_Textures[stage] = texture;
}
}
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
@@ -147,13 +156,13 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
PanicAlert("Invalid PC texture format %i", pcfmt);
case PC_TEX_FMT_BGRA32:
gl_format = GL_BGRA;
gl_iformat = 4;
gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_RGBA32:
gl_format = GL_RGBA;
gl_iformat = 4;
gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
@@ -195,36 +204,43 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
entry.gl_type = gl_type;
entry.pcfmt = pcfmt;
entry.bHaveMipMaps = tex_levels != 1;
entry.m_tex_levels = tex_levels;
entry.Load(width, height, expanded_width, 0);
return &entry;
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips)
unsigned int expanded_width, unsigned int level)
{
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
//GL_REPORT_ERRORD();
if (s_ActiveTexture != s_NextStage)
{
glActiveTexture(GL_TEXTURE0 + s_NextStage);
s_ActiveTexture = s_NextStage;
}
if (s_Textures[s_NextStage] != texture)
{
glBindTexture(GL_TEXTURE_2D, texture);
s_Textures[s_NextStage] = texture;
}
// TODO: sloppy, just do this on creation?
if (level == 0)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m_tex_levels - 1);
}
if (pcfmt != PC_TEX_FMT_DXT1)
{
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
if (bHaveMipMaps && autogen_mips)
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
}
else
{
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
}
glTexImage2D(GL_TEXTURE_2D, level, gl_iformat, width, height, 0, gl_format, gl_type, temp);
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
else
{
@@ -239,31 +255,26 @@ TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
{
TCacheEntry *const entry = new TCacheEntry;
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D, entry->texture);
GL_REPORT_ERRORD();
const GLenum
gl_format = GL_RGBA,
gl_iformat = 4,
gl_iformat = GL_RGBA,
gl_type = GL_UNSIGNED_BYTE;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
entry->m_tex_levels = 1;
glTexImage2D(GL_TEXTURE_2D, 0, gl_iformat, scaled_tex_w, scaled_tex_h, 0, gl_format, gl_type, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
SetStage();
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;
}
@@ -272,8 +283,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat)
{
glBindTexture(GL_TEXTURE_2D, texture);
g_renderer->ResetAPIState(); // reset any game specific settings
// Make sure to resolve anything we need to read from.
const GLuint read_texture = (srcFormat == PIXELFMT_Z24) ?
FramebufferManager::ResolveAndGetDepthTarget(srcRect) :
@@ -284,38 +295,85 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
if (s_TempFramebuffer == 0)
glGenFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
glGenFramebuffers(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);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 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);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_RECTANGLE, read_texture);
glViewport(0, 0, virtual_width, virtual_height);
PixelShaderCache::SetCurrentShader((srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram());
PixelShaderManager::SetColorMatrix(colmat); // set transformation
if(srcFormat == PIXELFMT_Z24) {
s_DepthMatrixProgram.Bind();
if(s_DepthCbufid != cbufid)
glUniform4fv(s_DepthMatrixUniform, 5, colmat);
s_DepthCbufid = cbufid;
} else {
s_ColorMatrixProgram.Bind();
if(s_ColorCbufid != cbufid)
glUniform4fv(s_ColorMatrixUniform, 7, colmat);
s_ColorCbufid = cbufid;
}
GL_REPORT_ERRORD();
TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
GL_REPORT_ERRORD();
// should be unique enough, if not, vbo will "only" be uploaded to much
u64 targetSourceHash = u64(targetSource.left)<<48 | u64(targetSource.top)<<32 | u64(targetSource.right)<<16 | u64(targetSource.bottom);
std::map<u64, VBOCache>::iterator vbo_it = s_VBO.find(targetSourceHash);
if(vbo_it == s_VBO.end()) {
VBOCache item;
item.targetSource.bottom = -1;
item.targetSource.top = -1;
item.targetSource.left = -1;
item.targetSource.right = -1;
glGenBuffers(1, &item.vbo);
glGenVertexArrays(1, &item.vao);
glBindBuffer(GL_ARRAY_BUFFER, item.vbo);
glBindVertexArray(item.vao);
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
vbo_it = s_VBO.insert(std::pair<u64,VBOCache>(targetSourceHash, item)).first;
}
if(!(vbo_it->second.targetSource == targetSource)) {
GLfloat vertices[] = {
-1.f, 1.f,
(GLfloat)targetSource.left, (GLfloat)targetSource.bottom,
-1.f, -1.f,
(GLfloat)targetSource.left, (GLfloat)targetSource.top,
1.f, -1.f,
(GLfloat)targetSource.right, (GLfloat)targetSource.top,
1.f, 1.f,
(GLfloat)targetSource.right, (GLfloat)targetSource.bottom
};
glBindBuffer(GL_ARRAY_BUFFER, vbo_it->second.vbo);
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
vbo_it->second.targetSource = targetSource;
}
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();
glBindVertexArray(vbo_it->second.vao);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
GL_REPORT_ERRORD();
// Unbind texture from temporary framebuffer
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
}
if (false == g_ActiveConfig.bCopyEFBToTexture)
@@ -330,20 +388,19 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
srcRect);
u8* dst = Memory::GetPointer(addr);
u64 hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
u64 const new_hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
if (!g_ActiveConfig.bEFBCopyCacheEnable)
TextureCache::MakeRangeDynamic(addr,encoded_size);
else if (!TextureCache::Find(addr, hash))
else if (!TextureCache::Find(addr, new_hash))
TextureCache::MakeRangeDynamic(addr,encoded_size);
this->hash = hash;
hash = new_hash;
}
FramebufferManager::SetFramebuffer(0);
VertexShaderManager::SetViewportChanged();
DisableStage(0);
GL_REPORT_ERRORD();
@@ -353,55 +410,97 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
SaveTexture(StringFromFormat("%sefb_frame_%i.tga", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
count++).c_str(), GL_TEXTURE_2D, texture, virtual_width, virtual_height, 0);
}
g_renderer->RestoreAPIState();
}
void TextureCache::TCacheEntry::SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1)
TextureCache::TextureCache()
{
// TODO: not used anywhere
TexMode0 mode = newmode;
//mode1 = newmode1;
const char *pColorMatrixProg =
"uniform sampler2DRect samp9;\n"
"uniform vec4 colmat[7];\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"\n"
"void main(){\n"
" vec4 texcol = texture2DRect(samp9, uv0);\n"
" texcol = round(texcol * colmat[5]) * colmat[6];\n"
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];\n"
"}\n";
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
(newmode.mag_filter || g_Config.bForceFiltering) ? GL_LINEAR : GL_NEAREST);
const char *pDepthMatrixProg =
"uniform sampler2DRect samp9;\n"
"uniform vec4 colmat[5];\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"\n"
"void main(){\n"
" vec4 texcol = texture2DRect(samp9, uv0);\n"
" vec4 EncodedDepth = fract((texcol.r * (16777215.0f/16777216.0f)) * vec4(1.0f,256.0f,256.0f*256.0f,1.0f));\n"
" texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * vec4(255.0f,255.0f,255.0f,15.0f)) / vec4(255.0f,255.0f,255.0f,15.0f);\n"
" ocol0 = texcol * mat4(colmat[0], colmat[1], colmat[2], colmat[3]) + colmat[4];"
"}\n";
if (bHaveMipMaps)
{
// TODO: not used anywhere
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));
const char *VProgram =
"in vec2 rawpos;\n"
"in vec2 tex0;\n"
"out vec2 uv0;\n"
"void main()\n"
"{\n"
" uv0 = tex0;\n"
" gl_Position = vec4(rawpos,0,1);\n"
"}\n";
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, VProgram, pColorMatrixProg);
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, VProgram, pDepthMatrixProg);
s_ColorMatrixUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "colmat");
s_DepthMatrixUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "colmat");
s_ColorCbufid = -1;
s_DepthCbufid = -1;
s_ActiveTexture = -1;
s_NextStage = -1;
for(int i=0; i<8; i++)
s_Textures[i] = -1;
}
TextureCache::~TextureCache()
{
if (s_TempFramebuffer)
s_ColorMatrixProgram.Destroy();
s_DepthMatrixProgram.Destroy();
for(std::map<u64, VBOCache>::iterator it = s_VBO.begin(); it != s_VBO.end(); it++) {
glDeleteBuffers(1, &it->second.vbo);
glDeleteVertexArrays(1, &it->second.vao);
}
s_VBO.clear();
if (s_TempFramebuffer)
{
glDeleteFramebuffersEXT(1, (GLuint*)&s_TempFramebuffer);
s_TempFramebuffer = 0;
}
glDeleteFramebuffers(1, (GLuint*)&s_TempFramebuffer);
s_TempFramebuffer = 0;
}
}
void TextureCache::DisableStage(unsigned int stage)
{
glActiveTexture(GL_TEXTURE0 + stage);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
}
void TextureCache::SetStage ()
{
// -1 is the initial value as we don't know which testure should be bound
if(s_ActiveTexture != (u32)-1)
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
}
void TextureCache::SetNextStage ( unsigned int stage )
{
s_NextStage = stage;
}
}
@@ -32,7 +32,10 @@ namespace OGL
class TextureCache : public ::TextureCache
{
public:
TextureCache();
static void DisableStage(unsigned int stage);
static void SetStage();
static void SetNextStage(unsigned int stage);
private:
struct TCacheEntry : TCacheEntryBase
@@ -45,7 +48,7 @@ private:
int gl_iformat;
int gl_type;
bool bHaveMipMaps;
int m_tex_levels;
//TexMode0 mode; // current filter and clamp modes that texture is set to
//TexMode1 mode1; // current filter and clamp modes that texture is set to
@@ -54,7 +57,7 @@ private:
~TCacheEntry();
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level, bool autogen_mips = false);
unsigned int expanded_width, unsigned int level);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
@@ -63,9 +66,6 @@ private:
void Bind(unsigned int stage);
bool Save(const char filename[], unsigned int level);
private:
void SetTextureParameters(const TexMode0 &newmode, const TexMode1 &newmode1);
};
~TextureCache();
@@ -23,7 +23,7 @@
#include "TextureConverter.h"
#include "TextureConversionShader.h"
#include "TextureCache.h"
#include "PixelShaderCache.h"
#include "ProgramShaderCache.h"
#include "VertexShaderManager.h"
#include "FramebufferManager.h"
#include "Globals.h"
@@ -50,64 +50,73 @@ 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;
static SHADER s_rgbToYuyvProgram;
static SHADER s_yuyvToRgbProgram;
// Not all slots are taken - but who cares.
const u32 NUM_ENCODING_PROGRAMS = 64;
static FRAGMENTSHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS];
void CreateRgbToYuyvProgram()
static GLuint s_encode_VBO = 0;
static GLuint s_encode_VAO = 0;
static GLuint s_decode_VBO = 0;
static GLuint s_decode_VAO = 0;
static TargetRectangle s_cached_sourceRc;
static int s_cached_srcWidth = 0;
static int s_cached_srcHeight = 0;
static const char *VProgram =
"in vec2 rawpos;\n"
"in vec2 tex0;\n"
"out vec2 uv0;\n"
"void main()\n"
"{\n"
" uv0 = tex0;\n"
" gl_Position = vec4(rawpos,0,1);\n"
"}\n";
void CreatePrograms()
{
// 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";
const char *FProgramRgbToYuyv =
"uniform sampler2DRect samp9;\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"void main()\n"
"{\n"
" vec3 c0 = texture2DRect(samp9, uv0).rgb;\n"
" vec3 c1 = texture2DRect(samp9, uv0 + vec2(1.0, 0.0)).rgb;\n"
" vec3 c01 = (c0 + c1) * 0.5;\n"
" vec3 y_const = vec3(0.257,0.504,0.098);\n"
" vec3 u_const = vec3(-0.148,-0.291,0.439);\n"
" vec3 v_const = vec3(0.439,-0.368,-0.071);\n"
" vec4 const3 = vec4(0.0625,0.5,0.0625f,0.5);\n"
" ocol0 = vec4(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.");
const char *FProgramYuyvToRgb =
"uniform sampler2DRect samp9;\n"
"in vec2 uv0;\n"
"out vec4 ocol0;\n"
"void main()\n"
"{\n"
" vec4 c0 = texture2DRect(samp9, uv0).rgba;\n"
" float f = step(0.5, fract(uv0.x));\n"
" float y = mix(c0.b, c0.r, f);\n"
" float yComp = 1.164f * (y - 0.0625f);\n"
" float uComp = c0.g - 0.5f;\n"
" float vComp = c0.a - 0.5f;\n"
" ocol0 = vec4(yComp + (1.596f * vComp),\n"
" yComp - (0.813f * vComp) - (0.391f * uComp),\n"
" yComp + (2.018f * uComp),\n"
" 1.0f);\n"
"}\n";
ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgram, FProgramRgbToYuyv);
ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgram, FProgramYuyvToRgb);
}
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)
SHADER &GetOrCreateEncodingShader(u32 format)
{
if (format > NUM_ENCODING_PROGRAMS)
{
@@ -117,7 +126,7 @@ FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
if (s_encodingPrograms[format].glprogid == 0)
{
const char* shader = TextureConversionShader::GenerateEncodingShader(format,API_OPENGL);
const char* shader = TextureConversionShader::GenerateEncodingShader(format, API_OPENGL);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader)
@@ -130,20 +139,43 @@ FRAGMENTSHADER &GetOrCreateEncodingShader(u32 format)
}
#endif
if (!PixelShaderCache::CompilePixelShader(s_encodingPrograms[format], shader)) {
ERROR_LOG(VIDEO, "Failed to create encoding fragment program");
}
ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader);
}
return s_encodingPrograms[format];
}
void Init()
{
glGenFramebuffersEXT(1, &s_texConvFrameBuffer);
glGenFramebuffers(1, &s_texConvFrameBuffer);
glGenBuffers(1, &s_encode_VBO );
glGenVertexArrays(1, &s_encode_VAO );
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
glBindVertexArray( s_encode_VAO );
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
s_cached_sourceRc.top = -1;
s_cached_sourceRc.bottom = -1;
s_cached_sourceRc.left = -1;
s_cached_sourceRc.right = -1;
glGenBuffers(1, &s_decode_VBO );
glGenVertexArrays(1, &s_decode_VAO );
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
glBindVertexArray( s_decode_VAO );
s_cached_srcWidth = -1;
s_cached_srcHeight = -1;
glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL);
glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB);
glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB, 2, GL_FLOAT, 0, sizeof(GLfloat)*4, (GLfloat*)NULL+2);
glGenRenderbuffersEXT(1, &s_dstRenderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, renderBufferWidth, renderBufferHeight);
glGenRenderbuffers(1, &s_dstRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, s_dstRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, renderBufferWidth, renderBufferHeight);
s_srcTextureWidth = 0;
s_srcTextureHeight = 0;
@@ -152,16 +184,20 @@ void Init()
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();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
CreatePrograms();
}
void Shutdown()
{
glDeleteTextures(1, &s_srcTexture);
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
glDeleteRenderbuffers(1, &s_dstRenderBuffer);
glDeleteFramebuffers(1, &s_texConvFrameBuffer);
glDeleteBuffers(1, &s_encode_VBO );
glDeleteVertexArrays(1, &s_encode_VAO );
glDeleteBuffers(1, &s_decode_VBO );
glDeleteVertexArrays(1, &s_decode_VAO );
s_rgbToYuyvProgram.Destroy();
s_yuyvToRgbProgram.Destroy();
@@ -174,8 +210,8 @@ void Shutdown()
s_texConvFrameBuffer = 0;
}
void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TargetRectangle& sourceRc,
u8* destAddr, int dstWidth, int dstHeight, int readStride,
void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc,
u8* destAddr, int dstWidth, int dstHeight, int readStride,
bool toTexture, bool linearFilter)
{
@@ -184,42 +220,52 @@ void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const Tar
// 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);
glBindRenderbuffer(GL_RENDERBUFFER, s_dstRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 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);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_RECTANGLE, 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);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE, 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);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
GL_REPORT_ERRORD();
glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);
PixelShaderCache::SetCurrentShader(shader.glprogid);
GL_REPORT_ERRORD();
if(!(s_cached_sourceRc == sourceRc)) {
GLfloat vertices[] = {
-1.f, -1.f,
(float)sourceRc.left, (float)sourceRc.top,
-1.f, 1.f,
(float)sourceRc.left, (float)sourceRc.bottom,
1.f, 1.f,
(float)sourceRc.right, (float)sourceRc.bottom,
1.f, -1.f,
(float)sourceRc.right, (float)sourceRc.top
};
glBindBuffer(GL_ARRAY_BUFFER, s_encode_VBO );
glBufferData(GL_ARRAY_BUFFER, 4*4*sizeof(GLfloat), vertices, GL_STREAM_DRAW);
s_cached_sourceRc = sourceRc;
}
// 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();
glBindVertexArray( s_encode_VAO );
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
GL_REPORT_ERRORD();
// .. and then read back the results.
@@ -266,9 +312,7 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
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;
SHADER& texconv_shader = GetOrCreateEncodingShader(format);
u8 *dest_ptr = Memory::GetPointer(address);
@@ -285,14 +329,18 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
// extra pixels are copied but not displayed in the resulting texture
s32 expandedWidth = (width + blkW) & (~blkW);
s32 expandedHeight = (height + blkH) & (~blkH);
float sampleStride = bScaleByHalf ? 2.f : 1.f;
TextureConversionShader::SetShaderParameters((float)expandedWidth,
(float)Renderer::EFBToScaledY(expandedHeight), // TODO: Why do we scale this?
(float)Renderer::EFBToScaledX(source.left),
(float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight),
Renderer::EFBToScaledXf(sampleStride),
Renderer::EFBToScaledYf(sampleStride));
float params[] = {
Renderer::EFBToScaledXf(sampleStride), Renderer::EFBToScaledYf(sampleStride),
0.0f, 0.0f,
(float)expandedWidth, (float)Renderer::EFBToScaledY(expandedHeight)-1,
(float)Renderer::EFBToScaledX(source.left), (float)Renderer::EFBToScaledY(EFB_HEIGHT - source.top - expandedHeight)
};
texconv_shader.Bind();
glUniform4fv(texconv_shader.UniformLocations[C_COLORS], 2, params);
TargetRectangle scaledSource;
scaledSource.top = 0;
@@ -305,7 +353,7 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
int readStride = (expandedWidth * cacheBytes) /
TexDecoder_GetBlockWidthInTexels(format);
EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource,
EncodeToRamUsingShader(source_texture, scaledSource,
dest_ptr, expandedWidth / samples, expandedHeight, readStride,
true, bScaleByHalf > 0 && !bFromZBuffer);
return size_in_bytes; // TODO: D3D11 is calculating this value differently!
@@ -315,10 +363,12 @@ int EncodeToRamFromTexture(u32 address,GLuint source_texture, bool bFromZBuffer,
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);
s_rgbToYuyvProgram.Bind();
EncodeToRamUsingShader(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();
@@ -326,7 +376,7 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des
// Should be scale free.
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture)
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destRenderbuf)
{
u8* srcAddr = Memory::GetPointer(xfbAddr);
if (!srcAddr)
@@ -342,51 +392,60 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur
// switch 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);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, destRenderbuf);
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);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_RECTANGLE, s_srcTexture);
// TODO: make this less slow. (How?)
if((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
if ((GLsizei)s_srcTextureWidth == (GLsizei)srcFmtWidth && (GLsizei)s_srcTextureHeight == (GLsizei)srcHeight)
{
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,0,0,s_srcTextureWidth, s_srcTextureHeight,
glTexSubImage2D(GL_TEXTURE_RECTANGLE, 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,
glTexImage2D(GL_TEXTURE_RECTANGLE, 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);
s_yuyvToRgbProgram.Bind();
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();
if(s_cached_srcHeight != srcHeight || s_cached_srcWidth != srcWidth) {
GLfloat vertices[] = {
1.f, -1.f,
(float)srcFmtWidth, (float)srcHeight,
1.f, 1.f,
(float)srcFmtWidth, 0.f,
-1.f, 1.f,
0.f, 0.f,
-1.f, -1.f,
0.f, (float)srcHeight
};
glBindBuffer(GL_ARRAY_BUFFER, s_decode_VBO );
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*4*4, vertices, GL_STREAM_DRAW);
s_cached_srcHeight = srcHeight;
s_cached_srcWidth = srcWidth;
}
glBindVertexArray( s_decode_VAO );
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GL_REPORT_ERRORD();
// 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();
@@ -35,7 +35,7 @@ void Shutdown();
void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc,
u8* destAddr, int dstWidth, int dstHeight);
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destRenderbuf);
// returns size of the encoded data (in bytes)
int EncodeToRamFromTexture(u32 address, GLuint source_texture, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source);
@@ -29,10 +29,9 @@
#include "ImageWrite.h"
#include "BPMemory.h"
#include "TextureCache.h"
#include "PixelShaderCache.h"
#include "PixelShaderManager.h"
#include "VertexShaderCache.h"
#include "VertexShaderManager.h"
#include "ProgramShaderCache.h"
#include "VertexShaderGen.h"
#include "VertexLoader.h"
#include "VertexManager.h"
@@ -40,6 +39,9 @@
#include "OpcodeDecoding.h"
#include "FileUtil.h"
#include "Debugger.h"
#include "StreamBuffer.h"
#include "PerfQueryBase.h"
#include "Render.h"
#include "main.h"
@@ -48,62 +50,117 @@ extern NativeVertexFormat *g_nativeVertexFmt;
namespace OGL
{
//This are the initially requeted size for the buffers expresed in bytes
const u32 MAX_IBUFFER_SIZE = 2*1024*1024;
const u32 MAX_VBUFFER_SIZE = 16*1024*1024;
//static GLint max_Index_size = 0;
//static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0};
//static int s_nCurVBOIndex = 0; // current free buffer
static StreamBuffer *s_vertexBuffer;
static StreamBuffer *s_indexBuffer;
static u32 s_baseVertex;
static u32 s_offset[3];
VertexManager::VertexManager()
{
// TODO: doesn't seem to be used anywhere
CreateDeviceObjects();
}
//glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*)&max_Index_size);
//
//if (max_Index_size > MAXIBUFFERSIZE)
// max_Index_size = MAXIBUFFERSIZE;
//
//GL_REPORT_ERRORD();
glEnableClientState(GL_VERTEX_ARRAY);
GL_REPORT_ERRORD();
VertexManager::~VertexManager()
{
DestroyDeviceObjects();
}
void VertexManager::CreateDeviceObjects()
{
s_vertexBuffer = new StreamBuffer(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE);
m_vertex_buffers = s_vertexBuffer->getBuffer();
s_indexBuffer = new StreamBuffer(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE, (StreamType)(DETECT_MASK & ~PINNED_MEMORY));
m_index_buffers = s_indexBuffer->getBuffer();
m_CurrentVertexFmt = NULL;
m_last_vao = 0;
}
void VertexManager::DestroyDeviceObjects()
{
GL_REPORT_ERRORD();
glBindBuffer(GL_ARRAY_BUFFER, 0 );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0 );
GL_REPORT_ERROR();
delete s_vertexBuffer;
delete s_indexBuffer;
GL_REPORT_ERROR();
}
void VertexManager::Draw()
void VertexManager::PrepareDrawBuffers(u32 stride)
{
if (IndexGenerator::GetNumTriangles() > 0)
u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride;
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
u32 line_index_size = IndexGenerator::GetLineindexLen();
u32 point_index_size = IndexGenerator::GetPointindexLen();
u32 index_size = (triangle_index_size+line_index_size+point_index_size) * sizeof(u16);
s_vertexBuffer->Alloc(vertex_data_size, stride);
u32 offset = s_vertexBuffer->Upload(GetVertexBuffer(), vertex_data_size);
s_baseVertex = offset / stride;
s_indexBuffer->Alloc(index_size);
if(triangle_index_size)
{
glDrawElements(GL_TRIANGLES, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT, TIBuffer);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
s_offset[0] = s_indexBuffer->Upload((u8*)GetTriangleIndexBuffer(), triangle_index_size * sizeof(u16));
}
if (IndexGenerator::GetNumLines() > 0)
if(line_index_size)
{
glDrawElements(GL_LINES, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT, LIBuffer);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
s_offset[1] = s_indexBuffer->Upload((u8*)GetLineIndexBuffer(), line_index_size * sizeof(u16));
}
if (IndexGenerator::GetNumPoints() > 0)
if(point_index_size)
{
glDrawElements(GL_POINTS, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT, PIBuffer);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
s_offset[2] = s_indexBuffer->Upload((u8*)GetPointIndexBuffer(), point_index_size * sizeof(u16));
}
}
void VertexManager::Draw(u32 stride)
{
u32 triangle_index_size = IndexGenerator::GetTriangleindexLen();
u32 line_index_size = IndexGenerator::GetLineindexLen();
u32 point_index_size = IndexGenerator::GetPointindexLen();
if(g_ogl_config.bSupportsGLBaseVertex) {
if (triangle_index_size > 0)
{
glDrawElementsBaseVertex(GL_TRIANGLES, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0], s_baseVertex);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (line_index_size > 0)
{
glDrawElementsBaseVertex(GL_LINES, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1], s_baseVertex);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (point_index_size > 0)
{
glDrawElementsBaseVertex(GL_POINTS, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2], s_baseVertex);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
} else {
if (triangle_index_size > 0)
{
glDrawElements(GL_TRIANGLES, triangle_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[0]);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (line_index_size > 0)
{
glDrawElements(GL_LINES, line_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[1]);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (point_index_size > 0)
{
glDrawElements(GL_POINTS, point_index_size, GL_UNSIGNED_SHORT, (u8*)NULL+s_offset[2]);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
}
}
void VertexManager::vFlush()
{
if (LocalVBuffer == s_pCurBufferPointer) return;
if (Flushed) return;
Flushed=true;
VideoFifo_CheckEFBAccess();
#if defined(_DEBUG) || defined(DEBUGFAST)
PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfregs.numTexGen.numTexGens,
xfregs.numChan.numColorChans, xfregs.dualTexTrans.enabled, bpmem.ztex2.op,
@@ -134,13 +191,15 @@ void VertexManager::vFlush()
(void)GL_REPORT_ERROR();
//glBindBuffer(GL_ARRAY_BUFFER, s_vboBuffers[s_nCurVBOIndex]);
//glBufferData(GL_ARRAY_BUFFER, s_pCurBufferPointer - LocalVBuffer, LocalVBuffer, GL_STREAM_DRAW);
GL_REPORT_ERRORD();
GLVertexFormat *nativeVertexFmt = (GLVertexFormat*)g_nativeVertexFmt;
u32 stride = nativeVertexFmt->GetVertexStride();
if(m_last_vao != nativeVertexFmt->VAO) {
glBindVertexArray(nativeVertexFmt->VAO);
m_last_vao = nativeVertexFmt->VAO;
}
// setup the pointers
if (g_nativeVertexFmt)
g_nativeVertexFmt->SetupVertexPointers();
PrepareDrawBuffers(stride);
GL_REPORT_ERRORD();
u32 usedtextures = 0;
@@ -153,19 +212,20 @@ void VertexManager::vFlush()
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
for (int i = 0; i < 8; i++)
for (u32 i = 0; i < 8; i++)
{
if (usedtextures & (1 << i))
{
glActiveTexture(GL_TEXTURE0 + i);
TextureCache::SetNextStage(i);
g_renderer->SetSamplerState(i % 4, i / 4);
FourTexUnits &tex = bpmem.tex[i >> 2];
TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i,
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3) && (tex.texMode0[i&3].min_filter != 8),
tex.texMode1[i&3].max_lod >> 4,
(tex.texMode0[i&3].min_filter & 3),
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
tex.texImage1[i&3].image_type);
if (tentry)
@@ -178,59 +238,64 @@ void VertexManager::vFlush()
}
}
// set global constants
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate
&& bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
#ifdef USE_DUAL_SOURCE_BLEND
bool dualSourcePossible = GLEW_ARB_blend_func_extended;
// Makes sure we can actually do Dual source blending
bool dualSourcePossible = g_ActiveConfig.backend_info.bSupportsDualSourceBlend;
// finally bind
FRAGMENTSHADER* ps;
if (dualSourcePossible)
{
if (useDstAlpha)
{
// If host supports GL_ARB_blend_func_extended, we can do dst alpha in
// the same pass as regular rendering.
g_renderer->SetBlendMode(true);
ps = PixelShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, g_nativeVertexFmt->m_components);
ProgramShaderCache::SetShader(DSTALPHA_DUAL_SOURCE_BLEND, g_nativeVertexFmt->m_components);
}
else
{
g_renderer->SetBlendMode(true);
ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
}
}
else
{
ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
ProgramShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
}
#else
bool dualSourcePossible = false;
FRAGMENTSHADER* ps = PixelShaderCache::SetShader(DSTALPHA_NONE,g_nativeVertexFmt->m_components);
#endif
VERTEXSHADER* vs = VertexShaderCache::SetShader(g_nativeVertexFmt->m_components);
if (ps) PixelShaderCache::SetCurrentShader(ps->glprogid); // Lego Star Wars crashes here.
if (vs) VertexShaderCache::SetCurrentShader(vs->glprogid);
Draw();
// set global constants
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
ProgramShaderCache::UploadConstants();
// setup the pointers
if (g_nativeVertexFmt)
g_nativeVertexFmt->SetupVertexPointers();
GL_REPORT_ERRORD();
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
Draw(stride);
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
//ERROR_LOG(VIDEO, "PerfQuery result: %d", g_perf_query->GetQueryResult(bpmem.zcontrol.early_ztest ? PQ_ZCOMP_OUTPUT_ZCOMPLOC : PQ_ZCOMP_OUTPUT));
// run through vertex groups again to set alpha
if (useDstAlpha && !dualSourcePossible)
{
ps = PixelShaderCache::SetShader(DSTALPHA_ALPHA_PASS,g_nativeVertexFmt->m_components);
if (ps) PixelShaderCache::SetCurrentShader(ps->glprogid);
ProgramShaderCache::SetShader(DSTALPHA_ALPHA_PASS,g_nativeVertexFmt->m_components);
if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
// Need to set these again, if we don't support UBO
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
}
// only update alpha
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glDisable(GL_BLEND);
Draw();
Draw(stride);
// restore color mask
g_renderer->SetColorMask();
@@ -238,22 +303,21 @@ void VertexManager::vFlush()
glEnable(GL_BLEND);
}
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
//s_nCurVBOIndex = (s_nCurVBOIndex + 1) % ARRAYSIZE(s_vboBuffers);
s_pCurBufferPointer = LocalVBuffer;
IndexGenerator::Start(TIBuffer,LIBuffer,PIBuffer);
#if defined(_DEBUG) || defined(DEBUGFAST)
if (g_ActiveConfig.iLog & CONF_SAVESHADERS)
{
// save the shaders
ProgramShaderCache::PCacheEntry prog = ProgramShaderCache::GetShaderProgram();
char strfile[255];
sprintf(strfile, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
std::ofstream fps(strfile);
fps << ps->strprog.c_str();
std::ofstream fps;
OpenFStream(fps, strfile, std::ios_base::out);
fps << prog.shader.strpprog.c_str();
sprintf(strfile, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), g_ActiveConfig.iSaveTargetId);
std::ofstream fvs(strfile);
fvs << vs->strprog.c_str();
std::ofstream fvs;
OpenFStream(fvs, strfile, std::ios_base::out);
fvs << prog.shader.strvprog.c_str();
}
if (g_ActiveConfig.iLog & CONF_SAVETARGETS)
@@ -24,6 +24,19 @@
namespace OGL
{
class GLVertexFormat : public NativeVertexFormat
{
PortableVertexDeclaration vtx_decl;
public:
GLVertexFormat();
~GLVertexFormat();
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
virtual void SetupVertexPointers();
GLuint VAO;
};
// Handles the OpenGL details of drawing lots of vertices quickly.
// Other functionality is moving out.
@@ -31,14 +44,20 @@ class VertexManager : public ::VertexManager
{
public:
VertexManager();
~VertexManager();
NativeVertexFormat* CreateNativeVertexFormat();
void CreateDeviceObjects();
void DestroyDeviceObjects();
// NativeVertexFormat use this
GLuint m_vertex_buffers;
GLuint m_index_buffers;
GLuint m_last_vao;
private:
void Draw();
// temp
void Draw(u32 stride);
void vFlush();
void PrepareDrawBuffers(u32 stride);
NativeVertexFormat *m_CurrentVertexFmt;
};
}
@@ -26,7 +26,7 @@
#include "Render.h"
#include "VertexShaderGen.h"
#include "VertexShaderManager.h"
#include "VertexShaderCache.h"
#include "ProgramShaderCache.h"
#include "VertexManager.h"
#include "VertexLoader.h"
#include "XFMemory.h"
@@ -37,235 +37,104 @@
namespace OGL
{
VertexShaderCache::VSCache VertexShaderCache::vshaders;
GLuint VertexShaderCache::CurrentShader;
bool VertexShaderCache::ShaderEnabled;
VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL;
VertexShaderUid VertexShaderCache::last_uid;
static int s_nMaxVertexInstructions;
void VertexShaderCache::Init()
void SetVSConstant4fvByName(const char * name, unsigned int offset, const float *f, const unsigned int count = 1)
{
glEnable(GL_VERTEX_PROGRAM_ARB);
ShaderEnabled = true;
CurrentShader = 0;
last_entry = NULL;
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
#if CG_VERSION_NUM == 2100
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
ProgramShaderCache::PCacheEntry tmp = ProgramShaderCache::GetShaderProgram();
for (int a = 0; a < NUM_UNIFORMS; ++a)
{
s_nMaxVertexInstructions = 4096;
}
#endif
}
void VertexShaderCache::Shutdown()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
iter->second.Destroy();
vshaders.clear();
}
VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
{
// Possible optimization: Don't always generate the shader uid, but keep track of changes in BPStructs instead
VertexShaderUid uid;
GetVertexShaderUid(uid, components, API_OPENGL);
if (last_entry)
{
if (uid == last_uid)
if (!strcmp(name, UniformNames[a]))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
if (tmp.shader.UniformLocations[a] == -1)
return;
else
{
glUniform4fv(tmp.shader.UniformLocations[a] + offset, count, f);
return;
}
}
}
last_uid = uid;
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end())
{
VSCacheEntry &entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
}
// Make an entry in the table
VSCacheEntry& entry = vshaders[uid];
last_entry = &entry;
VertexShaderCode code;
GenerateVertexShaderCode(code, 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).c_str(), counter++);
SaveData(szTemp, code.GetBuffer());
}
#endif
if (!code.GetBuffer() || !VertexShaderCache::CompileVertexShader(entry.shader, code.GetBuffer())) {
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return NULL;
}
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
}
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)) {
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
file << pstrprogram;
file.close();
PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%d):\n%s",
szTemp,
g_cgfProf,
cgGetLastListing(g_cgcontext));
cgDestroyProgram(tempprog);
ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
ERROR_LOG(VIDEO, "%s", pstrprogram);
return false;
}
if (cgGetError() != CG_NO_ERROR)
{
WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
WARN_LOG(VIDEO, "%s", 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, "%s", pstrprogram);
ERROR_LOG(VIDEO, "%s", pcompiledprog);
}
cgDestroyProgram(tempprog);
#endif
if (g_ActiveConfig.bEnableShaderDebugging)
vs.strprog = pstrprogram;
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);
}
}
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
float const buf[4] = {f1, f2, f3, f4};
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, 1);
return;
}
for (unsigned int a = 0; a < 9; ++a)
{
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
{
unsigned int offset = const_number - VSVar_Loc[a].reg;
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf);
return;
}
}
}
void Renderer::SetVSConstant4fv(unsigned int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, 1);
return;
}
for (unsigned int a = 0; a < 9; ++a)
{
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
{
unsigned int offset = const_number - VSVar_Loc[a].reg;
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f);
return;
}
}
}
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
{
if(GLEW_EXT_gpu_program_parameters)
{
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, f);
}
else
{
for (unsigned int i = 0; i < count; i++,f+=4)
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f);
}
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiVSConstant4fv(const_number, f, count);
return;
}
for (unsigned int a = 0; a < 9; ++a)
{
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
{
unsigned int offset = const_number - VSVar_Loc[a].reg;
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, f, count);
return;
}
}
}
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
{
if(GLEW_EXT_gpu_program_parameters)
float buf[4 * C_VENVCONST_END];
for (unsigned int i = 0; i < count; i++)
{
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;
}
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, buf);
}
else
{
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);
}
}
buf[4*i ] = *f++;
buf[4*i+1] = *f++;
buf[4*i+2] = *f++;
buf[4*i+3] = 0.f;
}
if (g_ActiveConfig.backend_info.bSupportsGLSLUBO)
{
ProgramShaderCache::SetMultiVSConstant4fv(const_number, buf, count);
return;
}
for (unsigned int a = 0; a < 9; ++a)
{
if (const_number >= VSVar_Loc[a].reg && const_number < ( VSVar_Loc[a].reg + VSVar_Loc[a].size))
{
unsigned int offset = const_number - VSVar_Loc[a].reg;
SetVSConstant4fvByName(VSVar_Loc[a].name, offset, buf, count);
return;
}
}
}
} // namespace OGL
@@ -1,271 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <math.h>
#include "Globals.h"
#include "VideoConfig.h"
#include "Statistics.h"
#include "GLUtil.h"
#include "Render.h"
#include "VertexShaderGen.h"
#include "VertexShaderManager.h"
#include "VertexShaderCache.h"
#include "VertexManager.h"
#include "VertexLoader.h"
#include "XFMemory.h"
#include "ImageWrite.h"
#include "FileUtil.h"
#include "Debugger.h"
namespace OGL
{
VertexShaderCache::VSCache VertexShaderCache::vshaders;
GLuint VertexShaderCache::CurrentShader;
bool VertexShaderCache::ShaderEnabled;
VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry = NULL;
VertexShaderUid VertexShaderCache::last_uid;
static int s_nMaxVertexInstructions;
void VertexShaderCache::Init()
{
glEnable(GL_VERTEX_PROGRAM_ARB);
ShaderEnabled = true;
CurrentShader = 0;
last_entry = NULL;
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, (GLint *)&s_nMaxVertexInstructions);
if (strstr((const char*)glGetString(GL_VENDOR), "Humper") != NULL) s_nMaxVertexInstructions = 4096;
#if CG_VERSION_NUM == 2100
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") != NULL)
{
s_nMaxVertexInstructions = 4096;
}
#endif
}
void VertexShaderCache::Shutdown()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
iter->second.Destroy();
vshaders.clear();
}
VERTEXSHADER* VertexShaderCache::SetShader(u32 components)
{
// Possible optimization: Don't always generate the shader uid, but keep track of changes in BPStructs instead
VertexShaderUid uid;
GetVertexShaderUid(uid, components, API_OPENGL);
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
}
}
last_uid = uid;
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end())
{
VSCacheEntry &entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
}
// Make an entry in the table
VSCacheEntry& entry = vshaders[uid];
last_entry = &entry;
ShaderCode code;
GenerateShaderCode(code, 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).c_str(), counter++);
SaveData(szTemp, code.GetBuffer());
}
#endif
if (!code.GetBuffer() || !VertexShaderCache::CompileVertexShader(entry.shader, code.GetBuffer())) {
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return NULL;
}
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, vshaders.size());
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return &last_entry->shader;
}
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)) {
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file(szTemp);
file << pstrprogram;
file.close();
PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%d):\n%s",
szTemp,
g_cgfProf,
cgGetLastListing(g_cgcontext));
cgDestroyProgram(tempprog);
ERROR_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
ERROR_LOG(VIDEO, "%s", pstrprogram);
return false;
}
if (cgGetError() != CG_NO_ERROR)
{
WARN_LOG(VIDEO, "Failed to load vs %s:", cgGetLastListing(g_cgcontext));
WARN_LOG(VIDEO, "%s", 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, "%s", pstrprogram);
ERROR_LOG(VIDEO, "%s", pcompiledprog);
}
cgDestroyProgram(tempprog);
#endif
if (g_ActiveConfig.bEnableShaderDebugging)
vs.strprog = pstrprogram;
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);
}
}
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, const_number, f1, f2, f3, f4);
}
void Renderer::SetVSConstant4fv(unsigned int const_number, const float *f)
{
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number, f);
}
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f)
{
if(GLEW_EXT_gpu_program_parameters)
{
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, f);
}
else
{
for (unsigned int i = 0; i < count; i++,f+=4)
glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, const_number + i, f);
}
}
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f)
{
if(GLEW_EXT_gpu_program_parameters)
{
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;
}
glProgramEnvParameters4fvEXT(GL_VERTEX_PROGRAM_ARB, const_number, count, buf);
}
else
{
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);
}
}
}
} // namespace OGL
@@ -1,76 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXSHADERCACHE_H_
#define _VERTEXSHADERCACHE_H_
#include <map>
#include <string>
#include "BPMemory.h"
#include "VertexShaderGen.h"
namespace OGL
{
struct VERTEXSHADER
{
VERTEXSHADER() : glprogid(0) {}
GLuint glprogid; // opengl program id
std::string strprog;
};
class VertexShaderCache
{
struct VSCacheEntry
{
VERTEXSHADER shader;
VertexShaderUid safe_uid;
VSCacheEntry() {}
void Destroy() {
// printf("Destroying vs %i\n", shader.glprogid);
glDeleteProgramsARB(1, &shader.glprogid);
shader.glprogid = 0;
}
};
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
static VSCache vshaders;
static VSCacheEntry* last_entry;
static VertexShaderUid last_uid; // TODO: Use reference instead..
static GLuint CurrentShader;
static bool ShaderEnabled;
public:
static void Init();
static void Shutdown();
static VERTEXSHADER* SetShader(u32 components);
static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
static void SetCurrentShader(GLuint Shader);
static void DisableShader();
};
} // namespace OGL
#endif // _VERTEXSHADERCACHE_H_
@@ -1,76 +0,0 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _VERTEXSHADERCACHE_H_
#define _VERTEXSHADERCACHE_H_
#include <map>
#include <string>
#include "BPMemory.h"
#include "VertexShaderGen.h"
namespace OGL
{
struct VERTEXSHADER
{
VERTEXSHADER() : glprogid(0) {}
GLuint glprogid; // opengl program id
std::string strprog;
};
class VertexShaderCache
{
struct VSCacheEntry
{
VERTEXSHADER shader;
VertexShaderUid safe_uid;
VSCacheEntry() {}
void Destroy() {
// printf("Destroying vs %i\n", shader.glprogid);
glDeleteProgramsARB(1, &shader.glprogid);
shader.glprogid = 0;
}
};
typedef std::map<ShaderUid, VSCacheEntry> VSCache;
static VSCache vshaders;
static VSCacheEntry* last_entry;
static ShaderUid last_uid; // TODO: Use reference instead..
static GLuint CurrentShader;
static bool ShaderEnabled;
public:
static void Init();
static void Shutdown();
static VERTEXSHADER* SetShader(u32 components);
static bool CompileVertexShader(VERTEXSHADER& ps, const char* pstrprogram);
static void SetCurrentShader(GLuint Shader);
static void DisableShader();
};
} // namespace OGL
#endif // _VERTEXSHADERCACHE_H_
@@ -15,6 +15,7 @@ class VideoBackend : public VideoBackendHardware
std::string GetName();
void Video_Prepare();
void Video_Cleanup();
void ShowConfig(void* parent);
+48 -32
View File
@@ -55,6 +55,7 @@ Make AA apply instantly during gameplay if possible
#include "LogManager.h"
#include <cstdarg>
#include <algorithm>
#ifdef _WIN32
#include "EmuWindow.h"
@@ -79,10 +80,9 @@ Make AA apply instantly during gameplay if possible
#include "VertexLoader.h"
#include "VertexLoaderManager.h"
#include "VertexManager.h"
#include "PixelShaderCache.h"
#include "PixelShaderManager.h"
#include "VertexShaderCache.h"
#include "VertexShaderManager.h"
#include "ProgramShaderCache.h"
#include "CommandProcessor.h"
#include "PixelEngine.h"
#include "TextureConverter.h"
@@ -92,6 +92,8 @@ Make AA apply instantly during gameplay if possible
#include "FramebufferManager.h"
#include "Core.h"
#include "Host.h"
#include "SamplerCache.h"
#include "PerfQuery.h"
#include "VideoState.h"
#include "VideoBackend.h"
@@ -107,36 +109,39 @@ std::string VideoBackend::GetName()
void GetShaders(std::vector<std::string> &shaders)
{
shaders.clear();
if (File::IsDirectory(File::GetUserPath(D_SHADERS_IDX)))
{
File::FSTEntry entry;
File::ScanDirectoryTree(File::GetUserPath(D_SHADERS_IDX), entry);
for (u32 i = 0; i < entry.children.size(); i++)
{
std::string name = entry.children[i].virtualName.c_str();
if (!strcasecmp(name.substr(name.size() - 4).c_str(), ".txt"))
name = name.substr(0, name.size() - 4);
shaders.push_back(name);
}
}
else
{
File::CreateDir(File::GetUserPath(D_SHADERS_IDX).c_str());
}
shaders.clear();
if (File::IsDirectory(File::GetUserPath(D_SHADERS_IDX)))
{
File::FSTEntry entry;
File::ScanDirectoryTree(File::GetUserPath(D_SHADERS_IDX), entry);
for (u32 i = 0; i < entry.children.size(); i++)
{
std::string name = entry.children[i].virtualName.c_str();
if (!strcasecmp(name.substr(name.size() - 4).c_str(), ".txt")) {
name = name.substr(0, name.size() - 4);
shaders.push_back(name);
}
}
std::sort(shaders.begin(), shaders.end());
}
else
{
File::CreateDir(File::GetUserPath(D_SHADERS_IDX).c_str());
}
}
void InitBackendInfo()
{
g_Config.backend_info.APIType = API_OPENGL;
g_Config.backend_info.bUseRGBATextures = false;
g_Config.backend_info.bUseRGBATextures = true;
g_Config.backend_info.bUseMinimalMipCount = false;
g_Config.backend_info.bSupports3DVision = false;
g_Config.backend_info.bSupportsDualSourceBlend = false; // supported, but broken
//g_Config.backend_info.bSupportsDualSourceBlend = true; // is gpu depenend and must be set in renderer
g_Config.backend_info.bSupportsFormatReinterpretation = false;
g_Config.backend_info.bSupportsPixelLighting = true;
// aamodes
const char* caamodes[] = {"None", "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA"};
const char* caamodes[] = {"None", "2x", "4x", "8x", "8x CSAA", "8xQ CSAA", "16x CSAA", "16xQ CSAA", "4x SSAA"};
g_Config.backend_info.AAModes.assign(caamodes, caamodes + sizeof(caamodes)/sizeof(*caamodes));
// pp shaders
@@ -189,21 +194,24 @@ void VideoBackend::Video_Prepare()
CommandProcessor::Init();
PixelEngine::Init();
g_texture_cache = new TextureCache;
BPInit();
g_vertex_manager = new VertexManager;
g_perf_query = new PerfQuery;
Fifo_Init(); // must be done before OpcodeDecoder_Init()
OpcodeDecoder_Init();
VertexShaderCache::Init();
VertexShaderManager::Init();
PixelShaderCache::Init();
PixelShaderManager::Init();
ProgramShaderCache::Init();
PostProcessing::Init();
g_texture_cache = new TextureCache();
g_sampler_cache = new SamplerCache();
Renderer::Init();
GL_REPORT_ERRORD();
VertexLoaderManager::Init();
TextureConverter::Init();
#ifndef _M_GENERIC
DLCache::Init();
#endif
// Notify the core that the video backend is ready
Host_Message(WM_USER_CREATE);
@@ -212,32 +220,40 @@ void VideoBackend::Video_Prepare()
void VideoBackend::Shutdown()
{
s_BackendInitialized = false;
GLInterface->Shutdown();
}
void VideoBackend::Video_Cleanup() {
if (g_renderer)
{
s_efbAccessRequested = false;
s_FifoShuttingDown = false;
s_swapRequested = false;
#ifndef _M_GENERIC
DLCache::Shutdown();
#endif
Fifo_Shutdown();
PostProcessing::Shutdown();
// The following calls are NOT Thread Safe
// And need to be called from the video thread
Renderer::Shutdown();
TextureConverter::Shutdown();
VertexLoaderManager::Shutdown();
VertexShaderCache::Shutdown();
delete g_sampler_cache;
g_sampler_cache = NULL;
delete g_texture_cache;
g_texture_cache = NULL;
PostProcessing::Shutdown();
ProgramShaderCache::Shutdown();
VertexShaderManager::Shutdown();
PixelShaderManager::Shutdown();
PixelShaderCache::Shutdown();
delete g_vertex_manager;
delete g_texture_cache;
g_vertex_manager = NULL;
OpcodeDecoder_Shutdown();
delete g_renderer;
g_renderer = NULL;
g_texture_cache = NULL;
}
GLInterface->Shutdown();
}
}
@@ -10,6 +10,7 @@ set(SRCS Src/BPMemLoader.cpp
Src/OpcodeDecoder.cpp
Src/SWPixelEngine.cpp
Src/Rasterizer.cpp
Src/RasterFont.cpp
Src/SWRenderer.cpp
Src/SetupUnit.cpp
Src/SWStatistics.cpp
@@ -184,6 +184,7 @@
<ClCompile Include="Src\OpcodeDecoder.cpp" />
<ClCompile Include="Src\SWPixelEngine.cpp" />
<ClCompile Include="Src\Rasterizer.cpp" />
<ClCompile Include="Src\RasterFont.cpp" />
<ClCompile Include="Src\SWRenderer.cpp" />
<ClCompile Include="Src\SetupUnit.cpp" />
<ClCompile Include="Src\SWStatistics.cpp" />
@@ -217,6 +218,7 @@
<ClInclude Include="Src\OpcodeDecoder.h" />
<ClInclude Include="Src\SWPixelEngine.h" />
<ClInclude Include="Src\Rasterizer.h" />
<ClInclude Include="Src\RasterFont.h" />
<ClInclude Include="Src\SWRenderer.h" />
<ClInclude Include="Src\SetupUnit.h" />
<ClInclude Include="Src\SWStatistics.h" />
@@ -13,6 +13,7 @@
<ClCompile Include="Src\OpcodeDecoder.cpp" />
<ClCompile Include="Src\SWPixelEngine.cpp" />
<ClCompile Include="Src\Rasterizer.cpp" />
<ClCompile Include="Src\RasterFont.cpp" />
<ClCompile Include="Src\SWRenderer.cpp" />
<ClCompile Include="Src\SetupUnit.cpp" />
<ClCompile Include="Src\SWStatistics.cpp" />
@@ -39,6 +40,7 @@
<ClInclude Include="Src\OpcodeDecoder.h" />
<ClInclude Include="Src\SWPixelEngine.h" />
<ClInclude Include="Src\Rasterizer.h" />
<ClInclude Include="Src\RasterFont.h" />
<ClInclude Include="Src\SWRenderer.h" />
<ClInclude Include="Src\SetupUnit.h" />
<ClInclude Include="Src\SWStatistics.h" />
@@ -90,6 +90,21 @@ void SWBPWritten(int address, int newvalue)
SWPixelEngine::pereg.boxBottom = newvalue >> 10;
SWPixelEngine::pereg.boxTop = newvalue & 0x3ff;
break;
case BPMEM_CLEAR_PIXEL_PERF:
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
SWPixelEngine::pereg.perfZcompInputZcomplocLo = 0;
SWPixelEngine::pereg.perfZcompInputZcomplocHi = 0;
SWPixelEngine::pereg.perfZcompOutputZcomplocLo = 0;
SWPixelEngine::pereg.perfZcompOutputZcomplocHi = 0;
SWPixelEngine::pereg.perfZcompInputLo = 0;
SWPixelEngine::pereg.perfZcompInputHi = 0;
SWPixelEngine::pereg.perfZcompOutputLo = 0;
SWPixelEngine::pereg.perfZcompOutputHi = 0;
SWPixelEngine::pereg.perfBlendInputLo = 0;
SWPixelEngine::pereg.perfBlendInputHi = 0;
SWPixelEngine::pereg.perfEfbCopyClocksLo = 0;
SWPixelEngine::pereg.perfEfbCopyClocksHi = 0;
break;
case BPMEM_LOADTLUT0: // This one updates bpmem.tlutXferSrc, no need to do anything here.
break;
case BPMEM_LOADTLUT1: // Load a Texture Look Up Table
@@ -65,6 +65,13 @@ namespace Clipper
OutputVertexData ClippedVertices[NUM_CLIPPED_VERTICES];
OutputVertexData *Vertices[NUM_INDICES];
void DoState(PointerWrap &p)
{
p.DoArray(m_ViewOffset,2);
for (int i = 0; i< NUM_CLIPPED_VERTICES; ++i)
ClippedVertices[i].DoState(p);
}
void Init()
{
for (int i = 0; i < NUM_CLIPPED_VERTICES; ++i)
@@ -21,6 +21,7 @@
#include "Common.h"
#include "NativeVertexFormat.h"
#include "ChunkFile.h"
namespace Clipper
@@ -36,6 +37,8 @@ namespace Clipper
bool CullTest(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2, bool &backface);
void PerspectiveDivide(OutputVertexData *vertex);
void DoState(PointerWrap &p);
}
@@ -28,6 +28,7 @@ u8 efb[EFB_WIDTH*EFB_HEIGHT*6];
namespace EfbInterface
{
u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4];
inline u32 GetColorOffset(u16 x, u16 y)
@@ -40,6 +41,12 @@ namespace EfbInterface
return (x + y * EFB_WIDTH) * 3 + DEPTH_BUFFER_START;
}
void DoState(PointerWrap &p)
{
p.DoArray(efb, EFB_WIDTH*EFB_HEIGHT*6);
p.DoArray(efbColorTexture, EFB_WIDTH*EFB_HEIGHT*4);
}
void SetPixelAlphaOnly(u32 offset, u8 a)
{
switch (bpmem.zcontrol.pixel_format)
@@ -454,10 +461,11 @@ namespace EfbInterface
SetPixelAlphaOnly(offset, color[ALP_C]);
}
void SetDepth(u16 x, u16 y, u32 depth)
{
SetPixelDepth(GetDepthOffset(x, y), depth);
}
void SetDepth(u16 x, u16 y, u32 depth)
{
if (bpmem.zmode.updateenable)
SetPixelDepth(GetDepthOffset(x, y), depth);
}
void GetColor(u16 x, u16 y, u8 *color)
{
@@ -47,6 +47,7 @@ namespace EfbInterface
void UpdateColorTexture();
extern u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4]; // RGBA format
void DoState(PointerWrap &p);
}
#endif
@@ -33,7 +33,7 @@ namespace HwRasterizer
float efbHalfHeight;
bool hasTexture;
u8 *temp;
u8 *temp;
// Programs
static GLuint colProg, texProg, clearProg;
@@ -61,7 +61,7 @@ namespace HwRasterizer
" gl_FragColor = " TEXFUNC "(Texture, TexCoordOut.xy);\n"
"}\n";
// Clear shader
static const char *fragclearText =
static const char *fragclearText =
"uniform " PREC " vec4 Color;\n"
"void main() {\n"
" gl_FragColor = Color;\n"
@@ -75,7 +75,7 @@ namespace HwRasterizer
" gl_Position = pos;\n"
" TexCoordOut = TexCoordIn;\n"
"}\n";
static const char *vertclearText =
static const char *vertclearText =
"attribute vec4 pos;\n"
"void main() {\n"
" gl_Position = pos;\n"
@@ -92,11 +92,11 @@ namespace HwRasterizer
// Color attributes
col_apos = glGetAttribLocation(colProg, "pos");
col_atex = glGetAttribLocation(colProg, "TexCoordIn");
col_atex = glGetAttribLocation(colProg, "TexCoordIn");
// Texture attributes
tex_apos = glGetAttribLocation(texProg, "pos");
tex_atex = glGetAttribLocation(texProg, "TexCoordIn");
tex_utex = glGetUniformLocation(texProg, "Texture");
tex_atex = glGetAttribLocation(texProg, "TexCoordIn");
tex_utex = glGetUniformLocation(texProg, "Texture");
// Clear attributes
clear_apos = glGetAttribLocation(clearProg, "pos");
clear_ucol = glGetUniformLocation(clearProg, "Color");
@@ -131,7 +131,7 @@ namespace HwRasterizer
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClientActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
@@ -179,7 +179,7 @@ namespace HwRasterizer
hasTexture = bpmem.tevorders[0].enable0;
if (hasTexture)
LoadTexture();
LoadTexture();
}
void EndTriangles()
@@ -204,15 +204,15 @@ namespace HwRasterizer
float z2 = v2->screenPosition.z / (float)0x00ffffff;
float r0 = v0->color[0][OutputVertexData::RED_C] / 255.0f;
float g0 = v0->color[0][OutputVertexData::GRN_C] / 255.0f;
float g0 = v0->color[0][OutputVertexData::GRN_C] / 255.0f;
float b0 = v0->color[0][OutputVertexData::BLU_C] / 255.0f;
float r1 = v1->color[0][OutputVertexData::RED_C] / 255.0f;
float g1 = v1->color[0][OutputVertexData::GRN_C] / 255.0f;
float g1 = v1->color[0][OutputVertexData::GRN_C] / 255.0f;
float b1 = v1->color[0][OutputVertexData::BLU_C] / 255.0f;
float r2 = v2->color[0][OutputVertexData::RED_C] / 255.0f;
float g2 = v2->color[0][OutputVertexData::GRN_C] / 255.0f;
float g2 = v2->color[0][OutputVertexData::GRN_C] / 255.0f;
float b2 = v2->color[0][OutputVertexData::BLU_C] / 255.0f;
static const GLfloat verts[3][3] = {
@@ -339,17 +339,17 @@ namespace HwRasterizer
texImage3.hex = texUnit.texImage3[0].hex;
texTlut.hex = texUnit.texTlut[0].hex;
int width = texImage0.width;
int height = texImage0.height;
int image_width = texImage0.width;
int image_height = texImage0.height;
DebugUtil::GetTextureBGRA(temp, 0, 0, width, height);
DebugUtil::GetTextureBGRA(temp, 0, 0, image_width, image_height);
glGenTextures(1, (GLuint *)&texture);
glBindTexture(TEX2D, texture);
#ifdef USE_GLES
glTexImage2D(TEX2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
glTexImage2D(TEX2D, 0, GL_RGBA, (GLsizei)image_width, (GLsizei)image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
#else
glTexImage2D(TEX2D, 0, GL_RGBA8, (GLsizei)width, (GLsizei)height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
glTexImage2D(TEX2D, 0, GL_RGBA8, (GLsizei)image_width, (GLsizei)image_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, temp);
#endif
GL_REPORT_ERRORD();
}
@@ -19,6 +19,7 @@
#define _NATIVEVERTEXFORMAT_H
#include "Vec3.h"
#include "ChunkFile.h"
#ifdef WIN32
#define LOADERDECL __cdecl
@@ -92,6 +93,18 @@ struct OutputVertexData
#undef LINTERP
#undef LINTERP_INT
}
void DoState(PointerWrap &p)
{
mvPosition.DoState(p);
p.Do(projectedPosition);
screenPosition.DoState(p);
for (int i = 0; i < 3;++i)
normal[i].DoState(p);
p.DoArray(color, sizeof color);
for (int i = 0; i < 8;++i)
texCoords[i].DoState(p);
}
};
#endif
@@ -35,7 +35,6 @@ typedef void (*DecodingFunction)(u32);
namespace OpcodeDecoder
{
static DecodingFunction currentFunction = NULL;
static u32 minCommandSize;
static u16 streamSize;
@@ -46,6 +45,20 @@ static bool inObjectStream;
static u8 lastPrimCmd;
void DoState(PointerWrap &p)
{
p.Do(minCommandSize);
// Not sure what is wrong with this. Something(s) in here is causing dolphin to crash/hang when loading states saved from another run of dolphin. Doesn't seem too important anyway...
//vertexLoader.DoState(p);
p.Do(readOpcode);
p.Do(inObjectStream);
p.Do(lastPrimCmd);
p.Do(streamSize);
p.Do(streamAddress);
if (p.GetMode() == PointerWrap::MODE_READ)
ResetDecoding();
}
void DecodePrimitiveStream(u32 iBufferSize)
{
u32 vertexSize = vertexLoader.GetVertexSize();
@@ -125,7 +138,9 @@ void DecodeStandard(u32 bufferSize)
if (Cmd == GX_NOP)
return;
// Causes a SIGBUS error on Android
// XXX: Investigate
#ifndef ANDROID
// check if switching in or out of an object
// only used for debuggging
if (inObjectStream && (Cmd & 0x87) != lastPrimCmd)
@@ -139,7 +154,7 @@ void DecodeStandard(u32 bufferSize)
lastPrimCmd = Cmd & 0x87;
DebugUtil::OnObjectBegin();
}
#endif
switch(Cmd)
{
case GX_NOP:
@@ -20,6 +20,7 @@
#define _OPCODEDECODER_H_
#include "CommonTypes.h"
#include "ChunkFile.h"
namespace OpcodeDecoder
{
@@ -57,6 +58,8 @@ namespace OpcodeDecoder
bool CommandRunnable(u32 iBufferSize);
void Run(u32 iBufferSize);
void DoState(PointerWrap &p);
}
#endif
@@ -0,0 +1,223 @@
// 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 "../../Plugin_VideoOGL/Src/GLUtil.h"
#include <string.h>
#include "RasterFont.h"
// globals
const GLubyte rasters[][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18},
{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70},
{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e},
{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c},
{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30},
{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03},
{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60},
{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e},
{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c},
{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60},
{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18},
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03},
{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e},
{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},
{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00},
{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78},
{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00},
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f},
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
};
RasterFont::RasterFont()
{
// set GL modes
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// create the raster font
fontOffset = glGenLists(128);
for (int i = 32; i < 127; i++) {
glNewList(i + fontOffset, GL_COMPILE);
glBitmap(8, 13, 0.0f, 2.0f, 10.0f, 0.0f, rasters[i - 32]);
glEndList();
}
temp_buffer = new char[TEMP_BUFFER_SIZE];
}
RasterFont::~RasterFont()
{
glDeleteLists(fontOffset, 128);
delete [] temp_buffer;
}
void RasterFont::printString(const char *s, double x, double y, double z)
{
int length = (int)strlen(s);
if (!length)
return;
if (length >= TEMP_BUFFER_SIZE)
length = TEMP_BUFFER_SIZE - 1;
// Sanitize string to avoid GL errors.
char *s2 = temp_buffer;
memcpy(s2, s, length);
s2[length] = 0;
for (int i = 0; i < length; i++) {
if (s2[i] < 32 || s2[i] > 126)
s2[i] = '!';
}
// go to the right spot
glRasterPos3d(x, y, z);
GL_REPORT_ERRORD();
glPushAttrib (GL_LIST_BIT);
glListBase(fontOffset);
glCallLists((GLsizei)strlen(s2), GL_UNSIGNED_BYTE, (GLubyte *) s2);
GL_REPORT_ERRORD();
glPopAttrib();
GL_REPORT_ERRORD();
}
void RasterFont::printCenteredString(const char *s, double y, int screen_width, double z)
{
int length = (int)strlen(s);
int x = (int)(screen_width/2.0 - (length/2.0)*char_width);
printString(s, x, y, z);
}
void RasterFont::printMultilineText(const char *text, double start_x, double start_y, double z, int bbWidth, int bbHeight)
{
double x = start_x;
double y = start_y;
char temp[1024];
char *t = temp;
while (*text)
{
if (*text == '\n')
{
*t = 0;
printString(temp, x, y, z);
y -= char_height * 2.0f / bbHeight;
x = start_x;
t = temp;
}
else if (*text == '\r')
{
t = temp;
}
else if (*text == '\t')
{
//todo: add tabs every something like 4*char_width
*t = 0;
int cpos = (int)strlen(temp);
int newpos = (cpos + 4) & (~3);
printString(temp, x, y, z);
x = start_x + (char_width*newpos) * 2.0f / bbWidth;
t = temp;
*t++ = ' ';
}
else
*t++ = *text;
text++;
}
// ????
if (t != text)
{
*t = 0;
printString(temp, x, y, z);
}
}
@@ -0,0 +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 _RASTERFONT_H_
#define _RASTERFONT_H_
class RasterFont {
public:
RasterFont();
~RasterFont(void);
static int debug;
// some useful constants
enum {char_width = 10};
enum {char_height = 15};
// and the happy helper functions
void printString(const char *s, double x, double y, double z=0.0);
void printCenteredString(const char *s, double y, int screen_width, double z=0.0);
void printMultilineText(const char *text, double x, double y, double z, int bbWidth, int bbHeight);
private:
int fontOffset;
char *temp_buffer;
enum {TEMP_BUFFER_SIZE = 64 * 1024};
};
#endif // _RASTERFONT_H_
@@ -23,6 +23,7 @@
#include "BPMemLoader.h"
#include "XFMemLoader.h"
#include "Tev.h"
#include "SWPixelEngine.h"
#include "SWStatistics.h"
#include "SWVideoConfig.h"
@@ -62,6 +63,28 @@ s32 scissorBottom = 0;
Tev tev;
RasterBlock rasterBlock;
void DoState(PointerWrap &p)
{
ZSlope.DoState(p);
WSlope.DoState(p);
for (int i=0;i<2;++i)
for (int n=0; n<4; ++n)
ColorSlopes[i][n].DoState(p);
for (int i=0;i<8;++i)
for (int n=0; n<3; ++n)
TexSlopes[i][n].DoState(p);
p.Do(vertex0X);
p.Do(vertex0Y);
p.Do(vertexOffsetX);
p.Do(vertexOffsetY);
p.Do(scissorLeft);
p.Do(scissorTop);
p.Do(scissorRight);
p.Do(scissorBottom);
tev.DoState(p);
p.Do(rasterBlock);
}
void Init()
{
tev.Init();
@@ -125,11 +148,17 @@ inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
if (z < 0 || z > 0x00ffffff)
return;
if (bpmem.zcontrol.early_ztest && bpmem.zmode.testenable)
if (bpmem.zcontrol.early_ztest && bpmem.zmode.testenable && g_SWVideoConfig.bZComploc)
{
// early z
if (!EfbInterface::ZCompare(x, y, z))
return;
// TODO: Test if perf regs are incremented even if test is disabled
SWPixelEngine::pereg.IncZInputQuadCount(true);
if (bpmem.zmode.testenable)
{
// early z
if (!EfbInterface::ZCompare(x, y, z))
return;
}
SWPixelEngine::pereg.IncZOutputQuadCount(true);
}
RasterBlockPixel& pixel = rasterBlock.Pixel[xi][yi];
@@ -369,7 +398,7 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
float w[3] = { 1.0f / v0->projectedPosition.w, 1.0f / v1->projectedPosition.w, 1.0f / v2->projectedPosition.w };
InitSlope(&WSlope, w[0], w[1], w[2], fltdx31, fltdx12, fltdy12, fltdy31);
if (!bpmem.genMode.zfreeze)
if (!bpmem.genMode.zfreeze || !g_SWVideoConfig.bZFreeze)
InitSlope(&ZSlope, v0->screenPosition[2], v1->screenPosition[2], v2->screenPosition[2], fltdx31, fltdx12, fltdy12, fltdy31);
for(unsigned int i = 0; i < bpmem.genMode.numcolchans; i++)
@@ -19,6 +19,7 @@
#define _RASTERIZER_H_
#include "NativeVertexFormat.h"
#include "ChunkFile.h"
namespace Rasterizer
{
@@ -37,6 +38,12 @@ namespace Rasterizer
float f0;
float GetValue(float dx, float dy) { return f0 + (dfdx * dx) + (dfdy * dy); }
void DoState(PointerWrap &p)
{
p.Do(dfdx);
p.Do(dfdy);
p.Do(f0);
}
};
struct RasterBlockPixel
@@ -53,6 +60,8 @@ namespace Rasterizer
s32 TextureLod[16];
bool TextureLinear[16];
};
void DoState(PointerWrap &p);
}
@@ -57,6 +57,15 @@ CPReg cpreg; // shared between gfx and emulator thread
void DoState(PointerWrap &p)
{
p.Do(cpreg);
p.DoArray(commandBuffer, commandBufferSize);
p.Do(readPos);
p.Do(writePos);
p.Do(et_UpdateInterrupts);
p.Do(interruptSet);
p.Do(interruptWaiting);
// Is this right?
p.DoArray(g_pVideoData,writePos);
}
// does it matter that there is no synchronization between threads during writes?
@@ -115,15 +124,15 @@ void RunGpu()
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
{
// We are going to do FP math on the main thread so have to save the current state
SaveSSEState();
LoadDefaultSSEState();
FPURoundMode::SaveSIMDState();
FPURoundMode::LoadDefaultSIMDState();
// run the opcode decoder
do {
RunBuffer();
} while (cpreg.ctrl.GPReadEnable && !AtBreakpoint() && cpreg.readptr != cpreg.writeptr);
LoadSSEState();
FPURoundMode::LoadSIMDState();
}
}
@@ -53,6 +53,8 @@ void DoState(PointerWrap &p)
p.Do(pereg);
p.Do(g_bSignalTokenInterrupt);
p.Do(g_bSignalFinishInterrupt);
p.Do(et_SetTokenOnMainThread);
p.Do(et_SetFinishOnMainThread);
}
void UpdateInterrupts();
@@ -77,7 +79,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress)
u16 address = _iAddress & 0xFFF;
if (address <= 0x16)
if (address <= 0x2e)
_uReturnValue = ((u16*)&pereg)[address >> 1];
}
@@ -109,7 +111,7 @@ void Write16(const u16 _iValue, const u32 _iAddress)
}
break;
default:
if (address <= 0x16)
if (address <= 0x2e)
((u16*)&pereg)[address >> 1] = _iValue;
break;
}
@@ -38,6 +38,21 @@ namespace SWPixelEngine
PE_BBOX_RIGHT = 0x012, // Flip Right
PE_BBOX_TOP = 0x014, // Flip Top
PE_BBOX_BOTTOM = 0x016, // Flip Bottom
// NOTE: Order not verified
// These indicate the number of quads that are being used as input/output for each particular stage
PE_PERF_ZCOMP_INPUT_ZCOMPLOC_L = 0x18,
PE_PERF_ZCOMP_INPUT_ZCOMPLOC_H = 0x1a,
PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_L = 0x1c,
PE_PERF_ZCOMP_OUTPUT_ZCOMPLOC_H = 0x1e,
PE_PERF_ZCOMP_INPUT_L = 0x20,
PE_PERF_ZCOMP_INPUT_H = 0x22,
PE_PERF_ZCOMP_OUTPUT_L = 0x24,
PE_PERF_ZCOMP_OUTPUT_H = 0x26,
PE_PERF_BLEND_INPUT_L = 0x28,
PE_PERF_BLEND_INPUT_H = 0x2a,
PE_PERF_EFB_COPY_CLOCKS_L = 0x2c,
PE_PERF_EFB_COPY_CLOCKS_H = 0x2e,
};
union UPEZConfReg
@@ -125,10 +140,72 @@ namespace SWPixelEngine
UPECtrlReg ctrl;
u16 unk0;
u16 token;
u16 boxLeft;
u16 boxRight;
u16 boxTop;
u16 boxBottom;
u16 perfZcompInputZcomplocLo;
u16 perfZcompInputZcomplocHi;
u16 perfZcompOutputZcomplocLo;
u16 perfZcompOutputZcomplocHi;
u16 perfZcompInputLo;
u16 perfZcompInputHi;
u16 perfZcompOutputLo;
u16 perfZcompOutputHi;
u16 perfBlendInputLo;
u16 perfBlendInputHi;
u16 perfEfbCopyClocksLo;
u16 perfEfbCopyClocksHi;
// NOTE: hardware doesn't process individual pixels but quads instead. Current software renderer architecture works on pixels though, so we have this "quad" hack here to only increment the registers on every fourth rendered pixel
void IncZInputQuadCount(bool early_ztest)
{
static int quad = 0;
if (++quad != 3)
return;
quad = 0;
if (early_ztest)
{
if (++perfZcompInputZcomplocLo == 0)
perfZcompInputZcomplocHi++;
}
else
{
if (++perfZcompInputLo == 0)
perfZcompInputHi++;
}
}
void IncZOutputQuadCount(bool early_ztest)
{
static int quad = 0;
if (++quad != 3)
return;
quad = 0;
if (early_ztest)
{
if (++perfZcompOutputZcomplocLo == 0)
perfZcompOutputZcomplocHi++;
}
else
{
if (++perfZcompOutputLo == 0)
perfZcompOutputHi++;
}
}
void IncBlendInputQuadCount()
{
static int quad = 0;
if (++quad != 3)
return;
quad = 0;
if (++perfBlendInputLo == 0)
perfBlendInputHi++;
}
};
extern PEReg pereg;
@@ -19,7 +19,7 @@
#include <math.h>
#include "../../Plugin_VideoOGL/Src/GLUtil.h"
#include "../../Plugin_VideoOGL/Src/RasterFont.h"
#include "RasterFont.h"
#include "SWRenderer.h"
#include "SWStatistics.h"
@@ -30,6 +30,7 @@ static GLint uni_tex = -1;
static GLuint program;
// Rasterfont isn't compatible with GLES
// degasus: I think it does, but I can't test it
#ifndef USE_GLES
RasterFont* s_pfont = NULL;
#endif
@@ -99,11 +100,11 @@ void SWRenderer::RenderText(const char* pstr, int left, int top, u32 color)
int nBackbufferWidth = (int)GLInterface->GetBackBufferWidth();
int nBackbufferHeight = (int)GLInterface->GetBackBufferHeight();
glColor4f(((color>>16) & 0xff)/255.0f, ((color>> 8) & 0xff)/255.0f,
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
((color>> 0) & 0xff)/255.0f, ((color>>24) & 0xFF)/255.0f);
s_pfont->printMultilineText(pstr,
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
left * 2.0f / (float)nBackbufferWidth - 1,
1 - top * 2.0f / (float)nBackbufferHeight,
0, nBackbufferWidth, nBackbufferHeight);
#endif
}
@@ -328,4 +328,15 @@ void SWVertexLoader::LoadTexCoord(SWVertexLoader *vertexLoader, InputVertexData
vertexLoader->m_texCoordLoader[index]();
}
void SWVertexLoader::DoState(PointerWrap &p)
{
p.DoArray(m_AttributeLoaders, sizeof m_AttributeLoaders);
p.Do(m_VertexSize);
p.Do(*m_CurrentVat);
p.Do(m_positionLoader);
p.Do(m_normalLoader);
p.DoArray(m_colorLoader, sizeof m_colorLoader);
p.Do(m_NumAttributeLoaders);
m_SetupUnit->DoState(p);
p.Do(m_TexGenSpecialCase);
}
@@ -22,6 +22,7 @@
#include "NativeVertexFormat.h"
#include "CPMemLoader.h"
#include "ChunkFile.h"
class SetupUnit;
@@ -69,7 +70,7 @@ public:
u32 GetVertexSize() { return m_VertexSize; }
void LoadVertex();
void DoState(PointerWrap &p);
};
#endif
@@ -23,35 +23,40 @@ SWVideoConfig g_SWVideoConfig;
SWVideoConfig::SWVideoConfig()
{
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bFullscreen = false;
bHideCursor = false;
renderToMainframe = false;
bHwRasterizer = false;
bShowStats = false;
bShowStats = false;
bDumpTextures = false;
bDumpObjects = false;
bDumpFrames = false;
bDumpTextures = false;
bDumpObjects = false;
bDumpFrames = false;
bDumpTevStages = false;
bZComploc = true;
bZFreeze = true;
bDumpTevStages = false;
bDumpTevTextureFetches = false;
drawStart = 0;
drawEnd = 100000;
drawStart = 0;
drawEnd = 100000;
}
void SWVideoConfig::Load(const char* ini_file)
{
std::string temp;
IniFile iniFile;
iniFile.Load(ini_file);
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
std::string temp;
IniFile iniFile;
iniFile.Load(ini_file);
iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware
iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false);
iniFile.Get("Rendering", "HwRasterizer", &bHwRasterizer, false);
iniFile.Get("Rendering", "ZComploc", &bZComploc, true);
iniFile.Get("Rendering", "ZFreeze", &bZFreeze, true);
iniFile.Get("Info", "ShowStats", &bShowStats, false);
@@ -67,13 +72,15 @@ void SWVideoConfig::Load(const char* ini_file)
void SWVideoConfig::Save(const char* ini_file)
{
IniFile iniFile;
iniFile.Load(ini_file);
IniFile iniFile;
iniFile.Load(ini_file);
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
iniFile.Set("Hardware", "Fullscreen", bFullscreen);
iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe);
iniFile.Set("Rendering", "HwRasterizer", bHwRasterizer);
iniFile.Set("Rendering", "ZComploc", &bZComploc);
iniFile.Set("Rendering", "ZFreeze", &bZFreeze);
iniFile.Set("Info", "ShowStats", bShowStats);
@@ -85,7 +92,7 @@ void SWVideoConfig::Save(const char* ini_file)
iniFile.Set("Misc", "DrawStart", drawStart);
iniFile.Set("Misc", "DrawEnd", drawEnd);
iniFile.Save(ini_file);
iniFile.Save(ini_file);
}
@@ -36,6 +36,10 @@ struct SWVideoConfig : NonCopyable
bool bHwRasterizer;
// Emulation features
bool bZComploc;
bool bZFreeze;
bool bShowStats;
bool bDumpTextures;
@@ -39,6 +39,9 @@
#include "FileUtil.h"
#include "VideoBackend.h"
#include "Core.h"
#include "OpcodeDecoder.h"
#include "SWVertexLoader.h"
#include "SWStatistics.h"
#define VSYNC_ENABLED 0
@@ -93,9 +96,33 @@ bool VideoSoftware::Initialize(void *&window_handle)
return true;
}
void VideoSoftware::DoState(PointerWrap&)
void VideoSoftware::DoState(PointerWrap& p)
{
// NYI
bool software = true;
p.Do(software);
if (p.GetMode() == PointerWrap::MODE_READ && software == false)
// change mode to abort load of incompatible save state.
p.SetMode(PointerWrap::MODE_VERIFY);
// TODO: incomplete?
SWCommandProcessor::DoState(p);
SWPixelEngine::DoState(p);
EfbInterface::DoState(p);
OpcodeDecoder::DoState(p);
Clipper::DoState(p);
p.Do(swxfregs);
p.Do(bpmem);
p.Do(swstats);
// CP Memory
p.DoArray(arraybases, 16);
p.DoArray(arraystrides, 16);
p.Do(MatrixIndexA);
p.Do(MatrixIndexB);
p.Do(g_VtxDesc.Hex);
p.DoArray(g_VtxAttr, 8);
p.DoMarker("CP Memory");
}
void VideoSoftware::CheckInvalidState()
@@ -132,18 +159,26 @@ void VideoSoftware::EmuStateChange(EMUSTATE_CHANGE newState)
void VideoSoftware::Shutdown()
{
// TODO: should be in Video_Cleanup
HwRasterizer::Shutdown();
SWRenderer::Shutdown();
GLInterface->Shutdown();
}
void VideoSoftware::Video_Cleanup()
{
}
// This is called after Video_Initialize() from the Core
void VideoSoftware::Video_Prepare()
{
GLInterface->MakeCurrent();
// Init extension support.
// Required for WGL SwapInterval
#ifndef USE_GLES
#ifdef __APPLE__
glewExperimental = 1;
#endif
if (glewInit() != GLEW_OK) {
ERROR_LOG(VIDEO, "glewInit() failed!Does your video card support OpenGL 2.x?");
return;
@@ -198,6 +233,12 @@ u32 VideoSoftware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputDa
return value;
}
u32 VideoSoftware::Video_GetQueryResult(PerfQueryType type)
{
// TODO:
return 0;
}
bool VideoSoftware::Video_Screenshot(const char *_szFilename)
{
return false;
@@ -25,13 +25,13 @@
void SetupUnit::Init(u8 primitiveType)
{
m_PrimType = primitiveType;
m_PrimType = primitiveType;
m_VertexCounter = 0;
m_VertPointer[0] = &m_Vertices[0];
m_VertPointer[1] = &m_Vertices[1];
m_VertPointer[2] = &m_Vertices[2];
m_VertWritePointer = m_VertPointer[0];
m_VertexCounter = 0;
m_VertPointer[0] = &m_Vertices[0];
m_VertPointer[1] = &m_Vertices[1];
m_VertPointer[2] = &m_Vertices[2];
m_VertWritePointer = m_VertPointer[0];
}
void SetupUnit::SetupVertex()
@@ -169,3 +169,21 @@ void SetupUnit::SetupLineStrip()
void SetupUnit::SetupPoint()
{}
void SetupUnit::DoState(PointerWrap &p)
{
// TODO: some or all of this is making the save states stop working once dolphin is closed...sometimes (usually)
// I have no idea what specifically is wrong, or if this is even important. Disabling it doesn't seem to make any noticible difference...
/* p.Do(m_PrimType);
p.Do(m_VertexCounter);
for (int i = 0; i < 3; ++i)
m_Vertices[i].DoState(p);
if (p.GetMode() == PointerWrap::MODE_READ)
{
m_VertPointer[0] = &m_Vertices[0];
m_VertPointer[1] = &m_Vertices[1];
m_VertPointer[2] = &m_Vertices[2];
m_VertWritePointer = m_VertPointer[0];
}*/
}
@@ -21,6 +21,7 @@
#include "Common.h"
#include "NativeVertexFormat.h"
#include "ChunkFile.h"
class SetupUnit
{
@@ -45,6 +46,7 @@ public:
OutputVertexData* GetVertex() { return m_VertWritePointer; }
void SetupVertex();
void DoState(PointerWrap &p);
};
#endif
+59 -10
View File
@@ -20,11 +20,13 @@
#include "Tev.h"
#include "EfbInterface.h"
#include "TextureSampler.h"
#include "XFMemLoader.h"
#include "SWPixelEngine.h"
#include "SWStatistics.h"
#include "SWVideoConfig.h"
#include "DebugUtil.h"
#include <math.h>
#include <cmath>
#ifdef _DEBUG
#define ALLOW_TEV_DUMPS 1
@@ -431,7 +433,7 @@ static bool AlphaCompare(int alpha, int ref, int comp)
return true;
}
static bool AlphaTest(int alpha)
static bool TevAlphaTest(int alpha)
{
bool comp0 = AlphaCompare(alpha, bpmem.alpha_test.ref0, bpmem.alpha_test.comp0);
bool comp1 = AlphaCompare(alpha, bpmem.alpha_test.ref1, bpmem.alpha_test.comp1);
@@ -700,7 +702,7 @@ void Tev::Draw()
// convert to 8 bits per component
u8 output[4] = {(u8)Reg[0][ALP_C], (u8)Reg[0][BLU_C], (u8)Reg[0][GRN_C], (u8)Reg[0][RED_C]};
if (!AlphaTest(output[ALP_C]))
if (!TevAlphaTest(output[ALP_C]))
return;
// z texture
@@ -747,10 +749,22 @@ void Tev::Draw()
}
// stuff to do!
// here, where we'll have to add/handle x range adjustment (if related BP register it's enabled)
// x_adjust = sqrt((x-center)^2 + k^2)/k
// ze *= x_adjust
if(bpmem.fogRange.Base.Enabled)
{
// TODO: This is untested and should definitely be checked against real hw.
// - No idea if offset is really normalized against the viewport width or against the projection matrix or yet something else
// - scaling of the "k" coefficient isn't clear either.
// First, calculate the offset from the viewport center (normalized to 0..1)
float offset = (Position[0] - (bpmem.fogRange.Base.Center - 342)) / (float)swxfregs.viewport.wd;
// Based on that, choose the index such that points which are far away from the z-axis use the 10th "k" value and such that central points use the first value.
int index = 9 - std::abs(offset) * 9.f;
index = (index < 0) ? 0 : (index > 9) ? 9 : 0; // TODO: Shouldn't be necessary!
// Look up coefficient... Seems like multiplying by 4 makes Fortune Street work properly (fog is too strong without the factor)
float k = bpmem.fogRange.K[index/2].GetValue(index%2) * 4.f;
float x_adjust = sqrt(offset*offset + k*k)/k;
ze *= x_adjust; // NOTE: This is basically dividing by a cosine (hidden behind GXInitFogAdjTable): 1/cos = c/b = sqrt(a^2+b^2)/b
}
ze -= bpmem.fog.c_proj_fsel.GetC();
@@ -784,11 +798,17 @@ void Tev::Draw()
output[BLU_C] = (output[BLU_C] * invFog + fogInt * bpmem.fog.color.b) >> 8;
}
if (!bpmem.zcontrol.early_ztest && bpmem.zmode.testenable)
{
bool late_ztest = !bpmem.zcontrol.early_ztest || !g_SWVideoConfig.bZComploc;
if (late_ztest && bpmem.zmode.testenable)
{
// TODO: Check against hw if these values get incremented even if depth testing is disabled
SWPixelEngine::pereg.IncZInputQuadCount(false);
if (!EfbInterface::ZCompare(Position[0], Position[1], Position[2]))
return;
}
SWPixelEngine::pereg.IncZOutputQuadCount(false);
}
#if ALLOW_TEV_DUMPS
if (g_SWVideoConfig.bDumpTevStages)
@@ -811,6 +831,7 @@ void Tev::Draw()
#endif
INCSTAT(swstats.thisFrame.tevPixelsOut);
SWPixelEngine::pereg.IncBlendInputQuadCount();
EfbInterface::BlendTev(Position[0], Position[1], output);
}
@@ -826,3 +847,31 @@ void Tev::SetRegColor(int reg, int comp, bool konst, s16 color)
Reg[reg][comp] = color;
}
}
void Tev::DoState(PointerWrap &p)
{
p.DoArray(Reg, sizeof(Reg));
p.DoArray(KonstantColors, sizeof(KonstantColors));
p.DoArray(TexColor,4);
p.DoArray(RasColor,4);
p.DoArray(StageKonst,4);
p.DoArray(Zero16,4);
p.DoArray(FixedConstants,9);
p.Do(AlphaBump);
p.DoArray(IndirectTex, sizeof(IndirectTex));
p.Do(TexCoord);
p.DoArray(m_BiasLUT,4);
p.DoArray(m_ScaleLShiftLUT,4);
p.DoArray(m_ScaleRShiftLUT,4);
p.DoArray(Position,3);
p.DoArray(Color, sizeof(Color));
p.DoArray(Uv, 8);
p.DoArray(IndirectLod,4);
p.DoArray(IndirectLinear,4);
p.DoArray(TextureLod,16);
p.DoArray(TextureLinear,16);
}
@@ -19,6 +19,7 @@
#define _TEV_H_
#include "BPMemLoader.h"
#include "ChunkFile.h"
class Tev
{
@@ -96,6 +97,8 @@ public:
void SetRegColor(int reg, int comp, bool konst, s16 color);
enum { ALP_C, BLU_C, GRN_C, RED_C };
void DoState(PointerWrap &p);
};
#endif
@@ -88,13 +88,13 @@ void TransformPosition(const InputVertexData *src, OutputVertexData *dst)
const float* mat = (const float*)&swxfregs.posMatrices[src->posMtx * 4];
MultiplyVec3Mat34(src->position, mat, dst->mvPosition);
if (swxfregs.projection[6] == 0)
if (swxfregs.projection.type == GX_PERSPECTIVE)
{
MultipleVec3Perspective(dst->mvPosition, swxfregs.projection, dst->projectedPosition);
MultipleVec3Perspective(dst->mvPosition, swxfregs.projection.rawProjection, dst->projectedPosition);
}
else
{
MultipleVec3Ortho(dst->mvPosition, swxfregs.projection, dst->projectedPosition);
MultipleVec3Ortho(dst->mvPosition, swxfregs.projection.rawProjection, dst->projectedPosition);
}
}
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <math.h>
#include "ChunkFile.h"
class Vec3
{
@@ -111,6 +112,12 @@ public:
{
memset((void *)this,0,sizeof(float)*3);
}
void DoState(PointerWrap &p)
{
p.Do(x);
p.Do(y);
p.Do(z);
}
};
#endif
@@ -21,12 +21,15 @@ class VideoSoftware : public VideoBackend
void ShowConfig(void* parent);
void Video_Prepare();
void Video_Cleanup();
void Video_EnterLoop();
void Video_ExitLoop();
void Video_BeginField(u32, FieldType, u32, u32);
void Video_EndField();
u32 Video_AccessEFB(EFBAccessType, u32, u32, u32);
u32 Video_GetQueryResult(PerfQueryType type);
void Video_AddMessage(const char* pstr, unsigned int milliseconds);
void Video_ClearMessages();
@@ -34,7 +34,7 @@ IntegerSetting<T>::IntegerSetting(wxWindow* parent, const wxString& label, T& se
VideoConfigDialog::VideoConfigDialog(wxWindow* parent, const std::string& title, const std::string& _ininame) :
wxDialog(parent, -1,
wxString(wxT("Dolphin ")).append(wxString::FromAscii(title.c_str())).append(wxT(" Graphics Configuration")),
wxString(wxT("Dolphin ")).append(StrToWxStr(title)).append(wxT(" Graphics Configuration")),
wxDefaultPosition, wxDefaultSize),
vconfig(g_SWVideoConfig),
ininame(_ininame)
@@ -64,10 +64,10 @@ VideoConfigDialog::VideoConfigDialog(wxWindow* parent, const std::string& title,
it = g_available_video_backends.begin(),
itend = g_available_video_backends.end();
for (; it != itend; ++it)
choice_backend->AppendString(wxString::FromAscii((*it)->GetName().c_str()));
choice_backend->AppendString(StrToWxStr((*it)->GetName()));
// TODO: How to get the translated plugin name?
choice_backend->SetStringSelection(wxString::FromAscii(g_video_backend->GetName().c_str()));
choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName()));
choice_backend->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &VideoConfigDialog::Event_Backend, this);
szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
@@ -85,6 +85,9 @@ struct Light
#define LIGHTATTN_NONE 2
#define LIGHTATTN_DIR 3
#define GX_PERSPECTIVE 0
#define GX_ORTHOGRAPHIC 1
union LitChannel
{
struct
@@ -160,6 +163,12 @@ struct Viewport
float farZ;
};
struct Projection
{
float rawProjection[6];
u32 type; // only GX_PERSPECTIVE or GX_ORTHOGRAPHIC are allowed
};
union TexMtxInfo
{
struct
@@ -218,7 +227,7 @@ struct XFRegisters
TXFMatrixIndexA MatrixIndexA; // 0x1018
TXFMatrixIndexB MatrixIndexB; // 0x1019
Viewport viewport; // 0x101a - 0x101f
float projection[7]; // 0x1020 - 0x1026
Projection projection; // 0x1020 - 0x1026
u32 unk8[24]; // 0x1027 - 0x103e
u32 numTexGens; // 0x103f
TexMtxInfo texMtxInfo[8]; // 0x1040 - 0x1047