1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
25 #include "VideoConfig.h"
26 #include "Statistics.h"
27 #include "MemoryUtil.h"
30 #include "ImageWrite.h"
32 #include "TextureCache.h"
33 #include "PixelShaderCache.h"
34 #include "PixelShaderManager.h"
35 #include "VertexShaderCache.h"
36 #include "VertexShaderManager.h"
37 #include "VertexShaderGen.h"
38 #include "VertexLoader.h"
39 #include "VertexManager.h"
40 #include "IndexGenerator.h"
41 #include "OpcodeDecoding.h"
46 // internal state for loading vertices
47 extern NativeVertexFormat
*g_nativeVertexFmt
;
52 //static GLint max_Index_size = 0;
54 //static GLuint s_vboBuffers[MAXVBOBUFFERCOUNT] = {0};
55 //static int s_nCurVBOIndex = 0; // current free buffer
57 VertexManager::VertexManager()
59 // TODO: doesn't seem to be used anywhere
61 //glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*)&max_Index_size);
63 //if (max_Index_size > MAXIBUFFERSIZE)
64 // max_Index_size = MAXIBUFFERSIZE;
68 glEnableClientState(GL_VERTEX_ARRAY
);
72 void VertexManager::Draw()
74 if (IndexGenerator::GetNumTriangles() > 0)
76 glDrawElements(GL_TRIANGLES
, IndexGenerator::GetTriangleindexLen(), GL_UNSIGNED_SHORT
, TIBuffer
);
77 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
79 if (IndexGenerator::GetNumLines() > 0)
81 glDrawElements(GL_LINES
, IndexGenerator::GetLineindexLen(), GL_UNSIGNED_SHORT
, LIBuffer
);
82 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
84 if (IndexGenerator::GetNumPoints() > 0)
86 glDrawElements(GL_POINTS
, IndexGenerator::GetPointindexLen(), GL_UNSIGNED_SHORT
, PIBuffer
);
87 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
91 void VertexManager::vFlush()
93 if (LocalVBuffer
== s_pCurBufferPointer
) return;
96 VideoFifo_CheckEFBAccess();
97 #if defined(_DEBUG) || defined(DEBUGFAST)
98 PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig
.iSaveTargetId
, xfregs
.numTexGens
,
99 xfregs
.nNumChans
, (int)xfregs
.bEnableDualTexTransform
, bpmem
.ztex2
.op
,
100 bpmem
.blendmode
.colorupdate
, bpmem
.blendmode
.alphaupdate
, bpmem
.zmode
.updateenable
);
102 for (int i
= 0; i
< xfregs
.nNumChans
; ++i
)
104 LitChannel
* ch
= &xfregs
.colChans
[i
].color
;
105 PRIM_LOG("colchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i
, ch
->matsource
, ch
->GetFullLightMask(), ch
->ambsource
, ch
->diffusefunc
, ch
->attnfunc
);
106 ch
= &xfregs
.colChans
[i
].alpha
;
107 PRIM_LOG("alpchan%d: matsrc=%d, light=0x%x, ambsrc=%d, diffunc=%d, attfunc=%d", i
, ch
->matsource
, ch
->GetFullLightMask(), ch
->ambsource
, ch
->diffusefunc
, ch
->attnfunc
);
110 for (int i
= 0; i
< xfregs
.numTexGens
; ++i
)
112 TexMtxInfo tinfo
= xfregs
.texcoords
[i
].texmtxinfo
;
113 if (tinfo
.texgentype
!= XF_TEXGEN_EMBOSS_MAP
) tinfo
.hex
&= 0x7ff;
114 if (tinfo
.texgentype
!= XF_TEXGEN_REGULAR
) tinfo
.projection
= 0;
116 PRIM_LOG("txgen%d: proj=%d, input=%d, gentype=%d, srcrow=%d, embsrc=%d, emblght=%d, postmtx=%d, postnorm=%d",
117 i
, tinfo
.projection
, tinfo
.inputform
, tinfo
.texgentype
, tinfo
.sourcerow
, tinfo
.embosssourceshift
, tinfo
.embosslightshift
,
118 xfregs
.texcoords
[i
].postmtxinfo
.index
, xfregs
.texcoords
[i
].postmtxinfo
.normalize
);
121 PRIM_LOG("pixel: tev=%d, ind=%d, texgen=%d, dstalpha=%d, alphafunc=0x%x", bpmem
.genMode
.numtevstages
+1, bpmem
.genMode
.numindstages
,
122 bpmem
.genMode
.numtexgens
, (u32
)bpmem
.dstalpha
.enable
, (bpmem
.alphaFunc
.hex
>>16)&0xff);
127 (void)GL_REPORT_ERROR();
129 //glBindBuffer(GL_ARRAY_BUFFER, s_vboBuffers[s_nCurVBOIndex]);
130 //glBufferData(GL_ARRAY_BUFFER, s_pCurBufferPointer - LocalVBuffer, LocalVBuffer, GL_STREAM_DRAW);
133 // setup the pointers
134 if (g_nativeVertexFmt
)
135 g_nativeVertexFmt
->SetupVertexPointers();
139 DVSTARTSUBPROFILE("VertexManager::Flush:textures");
141 u32 usedtextures
= 0;
142 for (u32 i
= 0; i
< (u32
)bpmem
.genMode
.numtevstages
+ 1; ++i
)
143 if (bpmem
.tevorders
[i
/ 2].getEnable(i
& 1))
144 usedtextures
|= 1 << bpmem
.tevorders
[i
/2].getTexMap(i
& 1);
146 if (bpmem
.genMode
.numindstages
> 0)
147 for (u32 i
= 0; i
< (u32
)bpmem
.genMode
.numtevstages
+ 1; ++i
)
148 if (bpmem
.tevind
[i
].IsActive() && bpmem
.tevind
[i
].bt
< bpmem
.genMode
.numindstages
)
149 usedtextures
|= 1 << bpmem
.tevindref
.getTexMap(bpmem
.tevind
[i
].bt
);
151 for (int i
= 0; i
< 8; i
++)
153 if (usedtextures
& (1 << i
))
155 glActiveTexture(GL_TEXTURE0
+ i
);
156 FourTexUnits
&tex
= bpmem
.tex
[i
>> 2];
157 TextureCache::TCacheEntry
* tentry
= TextureCache::Load(i
,
158 (tex
.texImage3
[i
&3].image_base
/* & 0x1FFFFF*/) << 5,
159 tex
.texImage0
[i
&3].width
+ 1, tex
.texImage0
[i
&3].height
+ 1,
160 tex
.texImage0
[i
&3].format
, tex
.texTlut
[i
&3].tmem_offset
<<9,
161 tex
.texTlut
[i
&3].tlut_format
);
165 // 0s are probably for no manual wrapping needed.
166 PixelShaderManager::SetTexDims(i
, tentry
->Realw
, tentry
->Realh
, 0, 0);
168 if (g_ActiveConfig
.iLog
& CONF_SAVETEXTURES
)
172 sprintf(strfile
, "%stex%.3d_%d.tga", File::GetUserPath(D_DUMPFRAMES_IDX
), g_Config
.iSaveTargetId
, i
);
173 SaveTexture(strfile
, GL_TEXTURE_2D
, tentry
->texture
, tentry
->w
, tentry
->h
);
177 ERROR_LOG(VIDEO
, "error loading texture");
181 // set global constants
182 VertexShaderManager::SetConstants();
183 PixelShaderManager::SetConstants();
186 FRAGMENTSHADER
* ps
= PixelShaderCache::SetShader(false,g_nativeVertexFmt
->m_components
);
187 VERTEXSHADER
* vs
= VertexShaderCache::SetShader(g_nativeVertexFmt
->m_components
);
188 if (ps
) PixelShaderCache::SetCurrentShader(ps
->glprogid
); // Lego Star Wars crashes here.
189 if (vs
) VertexShaderCache::SetCurrentShader(vs
->glprogid
);
193 // run through vertex groups again to set alpha
194 if (!g_ActiveConfig
.bDstAlphaPass
&& bpmem
.dstalpha
.enable
&& bpmem
.blendmode
.alphaupdate
)
196 ps
= PixelShaderCache::SetShader(true,g_nativeVertexFmt
->m_components
);
197 if (ps
) PixelShaderCache::SetCurrentShader(ps
->glprogid
);
200 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_TRUE
);
205 // restore color mask
206 Renderer::SetColorMask();
208 if (bpmem
.blendmode
.blendenable
|| bpmem
.blendmode
.subtract
)
211 //s_nCurVBOIndex = (s_nCurVBOIndex + 1) % ARRAYSIZE(s_vboBuffers);
212 s_pCurBufferPointer
= LocalVBuffer
;
213 IndexGenerator::Start(TIBuffer
,LIBuffer
,PIBuffer
);
215 #if defined(_DEBUG) || defined(DEBUGFAST)
216 if (g_ActiveConfig
.iLog
& CONF_SAVESHADERS
)
220 sprintf(strfile
, "%sps%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX
), g_ActiveConfig
.iSaveTargetId
);
221 std::ofstream
fps(strfile
);
222 fps
<< ps
->strprog
.c_str();
223 sprintf(strfile
, "%svs%.3d.txt", File::GetUserPath(D_DUMPFRAMES_IDX
), g_ActiveConfig
.iSaveTargetId
);
224 std::ofstream
fvs(strfile
);
225 fvs
<< vs
->strprog
.c_str();
228 if (g_ActiveConfig
.iLog
& CONF_SAVETARGETS
)
231 sprintf(str
, "%starg%.3d.tga", File::GetUserPath(D_DUMPFRAMES_IDX
), g_ActiveConfig
.iSaveTargetId
);
234 tr
.right
= Renderer::GetTargetWidth();
236 tr
.bottom
= Renderer::GetTargetHeight();
237 Renderer::SaveRenderTarget(str
, tr
);
240 g_Config
.iSaveTargetId
++;