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/
22 #include "D3DShader.h"
25 #include "Statistics.h"
27 #include "FramebufferManager.h"
28 #include "VertexManager.h"
29 #include "OpcodeDecoding.h"
30 #include "IndexGenerator.h"
31 #include "VertexShaderManager.h"
32 #include "VertexShaderCache.h"
33 #include "PixelShaderManager.h"
34 #include "PixelShaderCache.h"
35 #include "NativeVertexFormat.h"
36 #include "TextureCache.h"
39 #include "BPStructs.h"
40 #include "XFStructs.h"
44 // internal state for loading vertices
45 extern NativeVertexFormat
*g_nativeVertexFmt
;
50 // TODO: find sensible values for these two
53 NUM_VERTEXBUFFERS
= 8,
54 NUM_INDEXBUFFERS
= 10,
57 ID3D11Buffer
* indexbuffers
[NUM_INDEXBUFFERS
] = {};
58 ID3D11Buffer
* vertexbuffers
[NUM_VERTEXBUFFERS
] = {};
60 inline ID3D11Buffer
* GetSuitableIndexBuffer(const u32 minsize
)
62 for (u32 k
= 0; k
< NUM_INDEXBUFFERS
-1; ++k
)
63 if (minsize
> 2 * (((u32
)VertexManager::MAXIBUFFERSIZE
)>>(k
+1)))
64 return indexbuffers
[k
];
65 return indexbuffers
[NUM_INDEXBUFFERS
-1];
68 inline ID3D11Buffer
* GetSuitableVertexBuffer(const u32 minsize
)
70 for (u32 k
= 0; k
< NUM_VERTEXBUFFERS
-1; ++k
)
71 if (minsize
> (((u32
)VertexManager::MAXVBUFFERSIZE
)>>(k
+1)))
72 return vertexbuffers
[k
];
73 return vertexbuffers
[NUM_VERTEXBUFFERS
-1];
76 void CreateDeviceObjects()
78 D3D11_BUFFER_DESC bufdesc
= CD3D11_BUFFER_DESC(VertexManager::MAXIBUFFERSIZE
* 2,
79 D3D11_BIND_INDEX_BUFFER
, D3D11_USAGE_DYNAMIC
, D3D11_CPU_ACCESS_WRITE
);
80 for (u32 k
= 0; k
< NUM_INDEXBUFFERS
; ++k
, bufdesc
.ByteWidth
>>= 1)
82 CHECK(SUCCEEDED(D3D::device
->CreateBuffer(&bufdesc
, NULL
, indexbuffers
+ k
)),
83 "Failed to create index buffer [%i].", k
);
84 D3D::SetDebugObjectName((ID3D11DeviceChild
*)indexbuffers
[k
], "an index buffer of VertexManager");
87 bufdesc
.BindFlags
= D3D11_BIND_VERTEX_BUFFER
;
88 bufdesc
.ByteWidth
= VertexManager::MAXVBUFFERSIZE
;
89 for (u32 k
= 0; k
< NUM_VERTEXBUFFERS
; ++k
, bufdesc
.ByteWidth
>>= 1)
91 CHECK(SUCCEEDED(D3D::device
->CreateBuffer(&bufdesc
, NULL
, vertexbuffers
+ k
)),
92 "Failed to create vertex buffer [%i].", k
);
93 D3D::SetDebugObjectName((ID3D11DeviceChild
*)vertexbuffers
[k
], "a vertex buffer of VertexManager");
97 void DestroyDeviceObjects()
99 for (u32 k
= 0; k
< NUM_INDEXBUFFERS
; ++k
)
100 SAFE_RELEASE(indexbuffers
[k
]);
102 for (u32 k
= 0; k
< NUM_VERTEXBUFFERS
; ++k
)
103 SAFE_RELEASE(vertexbuffers
[k
]);
106 VertexManager::VertexManager()
108 CreateDeviceObjects();
111 VertexManager::~VertexManager()
113 DestroyDeviceObjects();
116 void VertexManager::Draw(u32 stride
, bool alphapass
)
118 D3D11_MAPPED_SUBRESOURCE map
;
119 ID3D11Buffer
* vertexbuffer
= GetSuitableVertexBuffer((u32
)(s_pCurBufferPointer
- LocalVBuffer
));
123 D3D::context
->Map(vertexbuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &map
);
124 memcpy(map
.pData
, LocalVBuffer
, (u32
)(s_pCurBufferPointer
- LocalVBuffer
));
125 D3D::context
->Unmap(vertexbuffer
, 0);
129 UINT bufstride
= stride
;
132 D3D::gfxstate
->ApplyState();
134 D3D::gfxstate
->AlphaPass();
136 if (IndexGenerator::GetNumTriangles() > 0)
138 u32 indexbuffersize
= IndexGenerator::GetTriangleindexLen();
139 ID3D11Buffer
* indexbuffer
= GetSuitableIndexBuffer(2*indexbuffersize
);
142 D3D::context
->Map(indexbuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &map
);
143 memcpy(map
.pData
, TIBuffer
, 2*indexbuffersize
);
144 D3D::context
->Unmap(indexbuffer
, 0);
147 D3D::context
->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
);
148 D3D::context
->IASetVertexBuffers(0, 1, &vertexbuffer
, &bufstride
, &bufoffset
);
149 D3D::context
->IASetIndexBuffer(indexbuffer
, DXGI_FORMAT_R16_UINT
, 0);
151 D3D::context
->DrawIndexed(indexbuffersize
, 0, 0);
152 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
154 if (IndexGenerator::GetNumLines() > 0)
156 u32 indexbuffersize
= IndexGenerator::GetLineindexLen();
157 ID3D11Buffer
* indexbuffer
= GetSuitableIndexBuffer(2*indexbuffersize
);
160 D3D::context
->Map(indexbuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &map
);
161 memcpy(map
.pData
, LIBuffer
, 2*indexbuffersize
);
162 D3D::context
->Unmap(indexbuffer
, 0);
165 D3D::context
->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST
);
166 D3D::context
->IASetVertexBuffers(0, 1, &vertexbuffer
, &bufstride
, &bufoffset
);
167 D3D::context
->IASetIndexBuffer(indexbuffer
, DXGI_FORMAT_R16_UINT
, 0);
169 D3D::context
->DrawIndexed(indexbuffersize
, 0, 0);
170 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
172 if (IndexGenerator::GetNumPoints() > 0)
174 u32 indexbuffersize
= IndexGenerator::GetPointindexLen();
175 ID3D11Buffer
* indexbuffer
= GetSuitableIndexBuffer(2*indexbuffersize
);
178 D3D::context
->Map(indexbuffer
, 0, D3D11_MAP_WRITE_DISCARD
, 0, &map
);
179 memcpy(map
.pData
, PIBuffer
, 2*indexbuffersize
);
180 D3D::context
->Unmap(indexbuffer
, 0);
183 D3D::context
->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST
);
184 D3D::context
->IASetVertexBuffers(0, 1, &vertexbuffer
, &bufstride
, &bufoffset
);
185 D3D::context
->IASetIndexBuffer(indexbuffer
, DXGI_FORMAT_R16_UINT
, 0);
187 D3D::context
->DrawIndexed(indexbuffersize
, 0, 0);
188 INCSTAT(stats
.thisFrame
.numIndexedDrawCalls
);
192 void VertexManager::vFlush()
194 if (LocalVBuffer
== s_pCurBufferPointer
) return;
197 VideoFifo_CheckEFBAccess();
201 u32 usedtextures
= 0;
202 for (u32 i
= 0; i
< (u32
)bpmem
.genMode
.numtevstages
+ 1; ++i
)
203 if (bpmem
.tevorders
[i
/ 2].getEnable(i
& 1))
204 usedtextures
|= 1 << bpmem
.tevorders
[i
/2].getTexMap(i
& 1);
206 if (bpmem
.genMode
.numindstages
> 0)
207 for (unsigned int i
= 0; i
< bpmem
.genMode
.numtevstages
+ 1; ++i
)
208 if (bpmem
.tevind
[i
].IsActive() && bpmem
.tevind
[i
].bt
< bpmem
.genMode
.numindstages
)
209 usedtextures
|= 1 << bpmem
.tevindref
.getTexMap(bpmem
.tevind
[i
].bt
);
211 for (unsigned int i
= 0; i
< 8; i
++)
213 if (usedtextures
& (1 << i
))
215 Renderer::SetSamplerState(i
& 3, i
>> 2);
216 FourTexUnits
&tex
= bpmem
.tex
[i
>> 2];
217 TextureCache::TCacheEntry
* tentry
= TextureCache::Load(i
,
218 (tex
.texImage3
[i
&3].image_base
/* & 0x1FFFFF*/) << 5,
219 tex
.texImage0
[i
&3].width
+ 1, tex
.texImage0
[i
&3].height
+ 1,
220 tex
.texImage0
[i
&3].format
, tex
.texTlut
[i
&3].tmem_offset
<<9,
221 tex
.texTlut
[i
&3].tlut_format
,
222 (tex
.texMode0
[i
&3].min_filter
& 3) && (tex
.texMode0
[i
&3].min_filter
!= 8) && g_ActiveConfig
.bUseNativeMips
,
223 (tex
.texMode1
[i
&3].max_lod
>> 4));
227 // 0s are probably for no manual wrapping needed.
228 PixelShaderManager::SetTexDims(i
, tentry
->w
, tentry
->h
, 0, 0);
231 ERROR_LOG(VIDEO
, "error loading texture");
235 // set global constants
236 VertexShaderManager::SetConstants();
237 PixelShaderManager::SetConstants();
239 if (!PixelShaderCache::SetShader(false,g_nativeVertexFmt
->m_components
))
241 if (!VertexShaderCache::SetShader(g_nativeVertexFmt
->m_components
))
244 unsigned int stride
= g_nativeVertexFmt
->GetVertexStride();
245 g_nativeVertexFmt
->SetupVertexPointers();
249 if (bpmem
.dstalpha
.enable
&& bpmem
.blendmode
.alphaupdate
)
252 if (!PixelShaderCache::SetShader(true,g_nativeVertexFmt
->m_components
))
258 D3D::gfxstate
->Reset();