1 // Copyright (c) 2013- PPSSPP Project.
2 
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 or later versions.
6 
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.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #include <algorithm>
19 
20 #include "Common/Data/Convert/ColorConv.h"
21 #include "Common/Profiler/Profiler.h"
22 #include "Core/Config.h"
23 #include "GPU/Common/DrawEngineCommon.h"
24 #include "GPU/Common/SplineCommon.h"
25 #include "GPU/Common/VertexDecoderCommon.h"
26 #include "GPU/ge_constants.h"
27 #include "GPU/GPUState.h"
28 
29 #define QUAD_INDICES_MAX 65536
30 
31 enum {
32 	TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)
33 };
34 
DrawEngineCommon()35 DrawEngineCommon::DrawEngineCommon() : decoderMap_(16) {
36 	decJitCache_ = new VertexDecoderJitCache();
37 	transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
38 	transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
39 }
40 
~DrawEngineCommon()41 DrawEngineCommon::~DrawEngineCommon() {
42 	FreeMemoryPages(transformed, TRANSFORMED_VERTEX_BUFFER_SIZE);
43 	FreeMemoryPages(transformedExpanded, 3 * TRANSFORMED_VERTEX_BUFFER_SIZE);
44 	delete decJitCache_;
45 	decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) {
46 		delete decoder;
47 	});
48 	ClearSplineBezierWeights();
49 }
50 
Init()51 void DrawEngineCommon::Init() {
52 	useHWTransform_ = g_Config.bHardwareTransform;
53 	useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation);
54 }
55 
GetVertexDecoder(u32 vtype)56 VertexDecoder *DrawEngineCommon::GetVertexDecoder(u32 vtype) {
57 	VertexDecoder *dec = decoderMap_.Get(vtype);
58 	if (dec)
59 		return dec;
60 	dec = new VertexDecoder();
61 	dec->SetVertexType(vtype, decOptions_, decJitCache_);
62 	decoderMap_.Insert(vtype, dec);
63 	return dec;
64 }
65 
ComputeNumVertsToDecode() const66 int DrawEngineCommon::ComputeNumVertsToDecode() const {
67 	int vertsToDecode = 0;
68 	if (drawCalls[0].indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) {
69 		for (int i = 0; i < numDrawCalls; i++) {
70 			const DeferredDrawCall &dc = drawCalls[i];
71 			vertsToDecode += dc.vertexCount;
72 		}
73 	} else {
74 		// TODO: Share this computation with DecodeVertsStep?
75 		for (int i = 0; i < numDrawCalls; i++) {
76 			const DeferredDrawCall &dc = drawCalls[i];
77 			int lastMatch = i;
78 			const int total = numDrawCalls;
79 			int indexLowerBound = dc.indexLowerBound;
80 			int indexUpperBound = dc.indexUpperBound;
81 			for (int j = i + 1; j < total; ++j) {
82 				if (drawCalls[j].verts != dc.verts)
83 					break;
84 
85 				indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound);
86 				indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound);
87 				lastMatch = j;
88 			}
89 			vertsToDecode += indexUpperBound - indexLowerBound + 1;
90 			i = lastMatch;
91 		}
92 	}
93 	return vertsToDecode;
94 }
95 
DecodeVerts(u8 * dest)96 void DrawEngineCommon::DecodeVerts(u8 *dest) {
97 	const UVScale origUV = gstate_c.uv;
98 	for (; decodeCounter_ < numDrawCalls; decodeCounter_++) {
99 		gstate_c.uv = drawCalls[decodeCounter_].uvScale;
100 		DecodeVertsStep(dest, decodeCounter_, decodedVerts_);  // NOTE! DecodeVertsStep can modify decodeCounter_!
101 	}
102 	gstate_c.uv = origUV;
103 
104 	// Sanity check
105 	if (indexGen.Prim() < 0) {
106 		ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim());
107 		// Force to points (0)
108 		indexGen.AddPrim(GE_PRIM_POINTS, 0, true);
109 	}
110 }
111 
DebugGetVertexLoaderIDs()112 std::vector<std::string> DrawEngineCommon::DebugGetVertexLoaderIDs() {
113 	std::vector<std::string> ids;
114 	decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) {
115 		std::string id;
116 		id.resize(sizeof(vtype));
117 		memcpy(&id[0], &vtype, sizeof(vtype));
118 		ids.push_back(id);
119 	});
120 	return ids;
121 }
122 
DebugGetVertexLoaderString(std::string id,DebugShaderStringType stringType)123 std::string DrawEngineCommon::DebugGetVertexLoaderString(std::string id, DebugShaderStringType stringType) {
124 	u32 mapId;
125 	memcpy(&mapId, &id[0], sizeof(mapId));
126 	VertexDecoder *dec = decoderMap_.Get(mapId);
127 	return dec ? dec->GetString(stringType) : "N/A";
128 }
129 
130 struct Plane {
131 	float x, y, z, w;
SetPlane132 	void Set(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
TestPlane133 	float Test(float f[3]) const { return x * f[0] + y * f[1] + z * f[2] + w; }
134 };
135 
PlanesFromMatrix(float mtx[16],Plane planes[6])136 static void PlanesFromMatrix(float mtx[16], Plane planes[6]) {
137 	planes[0].Set(mtx[3]-mtx[0], mtx[7]-mtx[4], mtx[11]-mtx[8], mtx[15]-mtx[12]);  // Right
138 	planes[1].Set(mtx[3]+mtx[0], mtx[7]+mtx[4], mtx[11]+mtx[8], mtx[15]+mtx[12]);  // Left
139 	planes[2].Set(mtx[3]+mtx[1], mtx[7]+mtx[5], mtx[11]+mtx[9], mtx[15]+mtx[13]);  // Bottom
140 	planes[3].Set(mtx[3]-mtx[1], mtx[7]-mtx[5], mtx[11]-mtx[9], mtx[15]-mtx[13]);  // Top
141 	planes[4].Set(mtx[3]+mtx[2], mtx[7]+mtx[6], mtx[11]+mtx[10], mtx[15]+mtx[14]); // Near
142 	planes[5].Set(mtx[3]-mtx[2], mtx[7]-mtx[6], mtx[11]-mtx[10], mtx[15]-mtx[14]); // Far
143 }
144 
ClipToScreen(const Vec4f & coords)145 static Vec3f ClipToScreen(const Vec4f& coords) {
146 	float xScale = gstate.getViewportXScale();
147 	float xCenter = gstate.getViewportXCenter();
148 	float yScale = gstate.getViewportYScale();
149 	float yCenter = gstate.getViewportYCenter();
150 	float zScale = gstate.getViewportZScale();
151 	float zCenter = gstate.getViewportZCenter();
152 
153 	float x = coords.x * xScale / coords.w + xCenter;
154 	float y = coords.y * yScale / coords.w + yCenter;
155 	float z = coords.z * zScale / coords.w + zCenter;
156 
157 	// 16 = 0xFFFF / 4095.9375
158 	return Vec3f(x * 16, y * 16, z);
159 }
160 
ScreenToDrawing(const Vec3f & coords)161 static Vec3f ScreenToDrawing(const Vec3f& coords) {
162 	Vec3f ret;
163 	ret.x = (coords.x - gstate.getOffsetX16()) * (1.0f / 16.0f);
164 	ret.y = (coords.y - gstate.getOffsetY16()) * (1.0f / 16.0f);
165 	ret.z = coords.z;
166 	return ret;
167 }
168 
Resized()169 void DrawEngineCommon::Resized() {
170 	decJitCache_->Clear();
171 	lastVType_ = -1;
172 	dec_ = nullptr;
173 	decoderMap_.Iterate([&](const uint32_t vtype, VertexDecoder *decoder) {
174 		delete decoder;
175 	});
176 	decoderMap_.Clear();
177 	ClearTrackedVertexArrays();
178 
179 	useHWTransform_ = g_Config.bHardwareTransform;
180 	useHWTessellation_ = UpdateUseHWTessellation(g_Config.bHardwareTessellation);
181 }
182 
NormalizeVertices(u8 * outPtr,u8 * bufPtr,const u8 * inPtr,int lowerBound,int upperBound,u32 vertType,int * vertexSize)183 u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) {
184 	const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
185 	VertexDecoder *dec = GetVertexDecoder(vertTypeID);
186 	if (vertexSize)
187 		*vertexSize = dec->VertexSize();
188 	return DrawEngineCommon::NormalizeVertices(outPtr, bufPtr, inPtr, dec, lowerBound, upperBound, vertType);
189 }
190 
191 // This code has plenty of potential for optimization.
192 //
193 // It does the simplest and safest test possible: If all points of a bbox is outside a single of
194 // our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations.
TestBoundingBox(void * control_points,int vertexCount,u32 vertType,int * bytesRead)195 bool DrawEngineCommon::TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead) {
196 	SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12);
197 	float *verts = (float *)(decoded + 65536 * 18);
198 
199 	// Try to skip NormalizeVertices if it's pure positions. No need to bother with a vertex decoder
200 	// and a large vertex format.
201 	if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) {
202 		verts = (float *)control_points;
203 		*bytesRead = 3 * sizeof(float) * vertexCount;
204 	} else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) {
205 		const s8 *vtx = (const s8 *)control_points;
206 		for (int i = 0; i < vertexCount * 3; i++) {
207 			verts[i] = vtx[i] * (1.0f / 128.0f);
208 		}
209 		*bytesRead = 3 * sizeof(s8) * vertexCount;
210 	} else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) {
211 		const s16 *vtx = (const s16*)control_points;
212 		for (int i = 0; i < vertexCount * 3; i++) {
213 			verts[i] = vtx[i] * (1.0f / 32768.0f);
214 		}
215 		*bytesRead = 3 * sizeof(s16) * vertexCount;
216 	} else {
217 		// Simplify away bones and morph before proceeding
218 		u8 *temp_buffer = decoded + 65536 * 24;
219 		int vertexSize = 0;
220 		NormalizeVertices((u8 *)corners, temp_buffer, (u8 *)control_points, 0, vertexCount, vertType, &vertexSize);
221 		for (int i = 0; i < vertexCount; i++) {
222 			verts[i * 3] = corners[i].pos.x;
223 			verts[i * 3 + 1] = corners[i].pos.y;
224 			verts[i * 3 + 2] = corners[i].pos.z;
225 		}
226 		*bytesRead = vertexSize * vertexCount;
227 	}
228 
229 	Plane planes[6];
230 
231 	float world[16];
232 	float view[16];
233 	float worldview[16];
234 	float worldviewproj[16];
235 	ConvertMatrix4x3To4x4(world, gstate.worldMatrix);
236 	ConvertMatrix4x3To4x4(view, gstate.viewMatrix);
237 	Matrix4ByMatrix4(worldview, world, view);
238 	Matrix4ByMatrix4(worldviewproj, worldview, gstate.projMatrix);
239 	PlanesFromMatrix(worldviewproj, planes);
240 	for (int plane = 0; plane < 6; plane++) {
241 		int inside = 0;
242 		int out = 0;
243 		for (int i = 0; i < vertexCount; i++) {
244 			// Here we can test against the frustum planes!
245 			float value = planes[plane].Test(verts + i * 3);
246 			if (value < 0)
247 				out++;
248 			else
249 				inside++;
250 		}
251 
252 		if (inside == 0) {
253 			// All out
254 			return false;
255 		}
256 
257 		// Any out. For testing that the planes are in the right locations.
258 		// if (out != 0) return false;
259 	}
260 	return true;
261 }
262 
263 // TODO: This probably is not the best interface.
GetCurrentSimpleVertices(int count,std::vector<GPUDebugVertex> & vertices,std::vector<u16> & indices)264 bool DrawEngineCommon::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) {
265 	// This is always for the current vertices.
266 	u16 indexLowerBound = 0;
267 	u16 indexUpperBound = count - 1;
268 
269 	if (!Memory::IsValidAddress(gstate_c.vertexAddr))
270 		return false;
271 
272 	bool savedVertexFullAlpha = gstate_c.vertexFullAlpha;
273 
274 	if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
275 		const u8 *inds = Memory::GetPointer(gstate_c.indexAddr);
276 		const u16_le *inds16 = (const u16_le *)inds;
277 		const u32_le *inds32 = (const u32_le *)inds;
278 
279 		if (inds) {
280 			GetIndexBounds(inds, count, gstate.vertType, &indexLowerBound, &indexUpperBound);
281 			indices.resize(count);
282 			switch (gstate.vertType & GE_VTYPE_IDX_MASK) {
283 			case GE_VTYPE_IDX_8BIT:
284 				for (int i = 0; i < count; ++i) {
285 					indices[i] = inds[i];
286 				}
287 				break;
288 			case GE_VTYPE_IDX_16BIT:
289 				for (int i = 0; i < count; ++i) {
290 					indices[i] = inds16[i];
291 				}
292 				break;
293 			case GE_VTYPE_IDX_32BIT:
294 				WARN_LOG_REPORT_ONCE(simpleIndexes32, G3D, "SimpleVertices: Decoding 32-bit indexes");
295 				for (int i = 0; i < count; ++i) {
296 					// These aren't documented and should be rare.  Let's bounds check each one.
297 					if (inds32[i] != (u16)inds32[i]) {
298 						ERROR_LOG_REPORT_ONCE(simpleIndexes32Bounds, G3D, "SimpleVertices: Index outside 16-bit range");
299 					}
300 					indices[i] = (u16)inds32[i];
301 				}
302 				break;
303 			}
304 		} else {
305 			indices.clear();
306 		}
307 	} else {
308 		indices.clear();
309 	}
310 
311 	static std::vector<u32> temp_buffer;
312 	static std::vector<SimpleVertex> simpleVertices;
313 	temp_buffer.resize(std::max((int)indexUpperBound, 8192) * 128 / sizeof(u32));
314 	simpleVertices.resize(indexUpperBound + 1);
315 	NormalizeVertices((u8 *)(&simpleVertices[0]), (u8 *)(&temp_buffer[0]), Memory::GetPointer(gstate_c.vertexAddr), indexLowerBound, indexUpperBound, gstate.vertType);
316 
317 	float world[16];
318 	float view[16];
319 	float worldview[16];
320 	float worldviewproj[16];
321 	ConvertMatrix4x3To4x4(world, gstate.worldMatrix);
322 	ConvertMatrix4x3To4x4(view, gstate.viewMatrix);
323 	Matrix4ByMatrix4(worldview, world, view);
324 	Matrix4ByMatrix4(worldviewproj, worldview, gstate.projMatrix);
325 
326 	vertices.resize(indexUpperBound + 1);
327 	uint32_t vertType = gstate.vertType;
328 	for (int i = indexLowerBound; i <= indexUpperBound; ++i) {
329 		const SimpleVertex &vert = simpleVertices[i];
330 
331 		if ((vertType & GE_VTYPE_THROUGH) != 0) {
332 			if (vertType & GE_VTYPE_TC_MASK) {
333 				vertices[i].u = vert.uv[0];
334 				vertices[i].v = vert.uv[1];
335 			} else {
336 				vertices[i].u = 0.0f;
337 				vertices[i].v = 0.0f;
338 			}
339 			vertices[i].x = vert.pos.x;
340 			vertices[i].y = vert.pos.y;
341 			vertices[i].z = vert.pos.z;
342 			if (vertType & GE_VTYPE_COL_MASK) {
343 				memcpy(vertices[i].c, vert.color, sizeof(vertices[i].c));
344 			} else {
345 				memset(vertices[i].c, 0, sizeof(vertices[i].c));
346 			}
347 			vertices[i].nx = 0;  // No meaningful normals in through mode
348 			vertices[i].ny = 0;
349 			vertices[i].nz = 1.0f;
350 		} else {
351 			float clipPos[4];
352 			Vec3ByMatrix44(clipPos, vert.pos.AsArray(), worldviewproj);
353 			Vec3f screenPos = ClipToScreen(clipPos);
354 			Vec3f drawPos = ScreenToDrawing(screenPos);
355 
356 			if (vertType & GE_VTYPE_TC_MASK) {
357 				vertices[i].u = vert.uv[0] * (float)gstate.getTextureWidth(0);
358 				vertices[i].v = vert.uv[1] * (float)gstate.getTextureHeight(0);
359 			} else {
360 				vertices[i].u = 0.0f;
361 				vertices[i].v = 0.0f;
362 			}
363 			// Should really have separate coordinates for before and after transform.
364 			vertices[i].x = drawPos.x;
365 			vertices[i].y = drawPos.y;
366 			vertices[i].z = drawPos.z;
367 			if (vertType & GE_VTYPE_COL_MASK) {
368 				memcpy(vertices[i].c, vert.color, sizeof(vertices[i].c));
369 			} else {
370 				memset(vertices[i].c, 0, sizeof(vertices[i].c));
371 			}
372 			vertices[i].nx = vert.nrm.x;
373 			vertices[i].ny = vert.nrm.y;
374 			vertices[i].nz = vert.nrm.z;
375 		}
376 	}
377 
378 	gstate_c.vertexFullAlpha = savedVertexFullAlpha;
379 
380 	return true;
381 }
382 
383 // This normalizes a set of vertices in any format to SimpleVertex format, by processing away morphing AND skinning.
384 // The rest of the transform pipeline like lighting will go as normal, either hardware or software.
385 // The implementation is initially a bit inefficient but shouldn't be a big deal.
386 // An intermediate buffer of not-easy-to-predict size is stored at bufPtr.
NormalizeVertices(u8 * outPtr,u8 * bufPtr,const u8 * inPtr,VertexDecoder * dec,int lowerBound,int upperBound,u32 vertType)387 u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType) {
388 	// First, decode the vertices into a GPU compatible format. This step can be eliminated but will need a separate
389 	// implementation of the vertex decoder.
390 	dec->DecodeVerts(bufPtr, inPtr, lowerBound, upperBound);
391 
392 	// OK, morphing eliminated but bones still remain to be taken care of.
393 	// Let's do a partial software transform where we only do skinning.
394 
395 	VertexReader reader(bufPtr, dec->GetDecVtxFmt(), vertType);
396 
397 	SimpleVertex *sverts = (SimpleVertex *)outPtr;
398 
399 	const u8 defaultColor[4] = {
400 		(u8)gstate.getMaterialAmbientR(),
401 		(u8)gstate.getMaterialAmbientG(),
402 		(u8)gstate.getMaterialAmbientB(),
403 		(u8)gstate.getMaterialAmbientA(),
404 	};
405 
406 	// Let's have two separate loops, one for non skinning and one for skinning.
407 	if (!g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) {
408 		int numBoneWeights = vertTypeGetNumBoneWeights(vertType);
409 		for (int i = lowerBound; i <= upperBound; i++) {
410 			reader.Goto(i - lowerBound);
411 			SimpleVertex &sv = sverts[i];
412 			if (vertType & GE_VTYPE_TC_MASK) {
413 				reader.ReadUV(sv.uv);
414 			}
415 
416 			if (vertType & GE_VTYPE_COL_MASK) {
417 				reader.ReadColor0_8888(sv.color);
418 			} else {
419 				memcpy(sv.color, defaultColor, 4);
420 			}
421 
422 			float nrm[3], pos[3];
423 			float bnrm[3], bpos[3];
424 
425 			if (vertType & GE_VTYPE_NRM_MASK) {
426 				// Normals are generated during tessellation anyway, not sure if any need to supply
427 				reader.ReadNrm(nrm);
428 			} else {
429 				nrm[0] = 0;
430 				nrm[1] = 0;
431 				nrm[2] = 1.0f;
432 			}
433 			reader.ReadPos(pos);
434 
435 			// Apply skinning transform directly
436 			float weights[8];
437 			reader.ReadWeights(weights);
438 			// Skinning
439 			Vec3Packedf psum(0, 0, 0);
440 			Vec3Packedf nsum(0, 0, 0);
441 			for (int w = 0; w < numBoneWeights; w++) {
442 				if (weights[w] != 0.0f) {
443 					Vec3ByMatrix43(bpos, pos, gstate.boneMatrix + w * 12);
444 					Vec3Packedf tpos(bpos);
445 					psum += tpos * weights[w];
446 
447 					Norm3ByMatrix43(bnrm, nrm, gstate.boneMatrix + w * 12);
448 					Vec3Packedf tnorm(bnrm);
449 					nsum += tnorm * weights[w];
450 				}
451 			}
452 			sv.pos = psum;
453 			sv.nrm = nsum;
454 		}
455 	} else {
456 		for (int i = lowerBound; i <= upperBound; i++) {
457 			reader.Goto(i - lowerBound);
458 			SimpleVertex &sv = sverts[i];
459 			if (vertType & GE_VTYPE_TC_MASK) {
460 				reader.ReadUV(sv.uv);
461 			} else {
462 				sv.uv[0] = 0.0f;  // This will get filled in during tessellation
463 				sv.uv[1] = 0.0f;
464 			}
465 			if (vertType & GE_VTYPE_COL_MASK) {
466 				reader.ReadColor0_8888(sv.color);
467 			} else {
468 				memcpy(sv.color, defaultColor, 4);
469 			}
470 			if (vertType & GE_VTYPE_NRM_MASK) {
471 				// Normals are generated during tessellation anyway, not sure if any need to supply
472 				reader.ReadNrm((float *)&sv.nrm);
473 			} else {
474 				sv.nrm.x = 0.0f;
475 				sv.nrm.y = 0.0f;
476 				sv.nrm.z = 1.0f;
477 			}
478 			reader.ReadPos((float *)&sv.pos);
479 		}
480 	}
481 
482 	// Okay, there we are! Return the new type (but keep the index bits)
483 	return GE_VTYPE_TC_FLOAT | GE_VTYPE_COL_8888 | GE_VTYPE_NRM_FLOAT | GE_VTYPE_POS_FLOAT | (vertType & (GE_VTYPE_IDX_MASK | GE_VTYPE_THROUGH));
484 }
485 
ApplyFramebufferRead(bool * fboTexNeedsBind)486 bool DrawEngineCommon::ApplyFramebufferRead(bool *fboTexNeedsBind) {
487 	if (gstate_c.Supports(GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH)) {
488 		*fboTexNeedsBind = false;
489 		return true;
490 	}
491 
492 	static const int MAX_REASONABLE_BLITS_PER_FRAME = 24;
493 
494 	static int lastFrameBlit = -1;
495 	static int blitsThisFrame = 0;
496 	if (lastFrameBlit != gpuStats.numFlips) {
497 		if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME) {
498 			WARN_LOG_REPORT_ONCE(blendingBlit, G3D, "Lots of blits needed for obscure blending: %d per frame, blend %d/%d/%d", blitsThisFrame, gstate.getBlendFuncA(), gstate.getBlendFuncB(), gstate.getBlendEq());
499 		}
500 		blitsThisFrame = 0;
501 		lastFrameBlit = gpuStats.numFlips;
502 	}
503 	++blitsThisFrame;
504 	if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME * 2) {
505 		WARN_LOG_ONCE(blendingBlit2, G3D, "Skipping additional blits needed for obscure blending: %d per frame, blend %d/%d/%d", blitsThisFrame, gstate.getBlendFuncA(), gstate.getBlendFuncB(), gstate.getBlendEq());
506 		return false;
507 	}
508 
509 	*fboTexNeedsBind = true;
510 
511 	gstate_c.Dirty(DIRTY_SHADERBLEND);
512 	return true;
513 }
514 
DecodeVertsStep(u8 * dest,int & i,int & decodedVerts)515 void DrawEngineCommon::DecodeVertsStep(u8 *dest, int &i, int &decodedVerts) {
516 	PROFILE_THIS_SCOPE("vertdec");
517 
518 	const DeferredDrawCall &dc = drawCalls[i];
519 
520 	indexGen.SetIndex(decodedVerts);
521 	int indexLowerBound = dc.indexLowerBound;
522 	int indexUpperBound = dc.indexUpperBound;
523 
524 	if (dc.indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) {
525 		// Decode the verts and apply morphing. Simple.
526 		dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride,
527 			dc.verts, indexLowerBound, indexUpperBound);
528 		decodedVerts += indexUpperBound - indexLowerBound + 1;
529 
530 		bool clockwise = true;
531 		if (gstate.isCullEnabled() && gstate.getCullMode() != dc.cullMode) {
532 			clockwise = false;
533 		}
534 		indexGen.AddPrim(dc.prim, dc.vertexCount, clockwise);
535 	} else {
536 		// It's fairly common that games issue long sequences of PRIM calls, with differing
537 		// inds pointer but the same base vertex pointer. We'd like to reuse vertices between
538 		// these as much as possible, so we make sure here to combine as many as possible
539 		// into one nice big drawcall, sharing data.
540 
541 		// 1. Look ahead to find the max index, only looking as "matching" drawcalls.
542 		//    Expand the lower and upper bounds as we go.
543 		int lastMatch = i;
544 		const int total = numDrawCalls;
545 		for (int j = i + 1; j < total; ++j) {
546 			if (drawCalls[j].verts != dc.verts)
547 				break;
548 
549 			indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound);
550 			indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound);
551 			lastMatch = j;
552 		}
553 
554 		// 2. Loop through the drawcalls, translating indices as we go.
555 		switch (dc.indexType) {
556 		case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT:
557 			for (int j = i; j <= lastMatch; j++) {
558 				bool clockwise = true;
559 				if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
560 					clockwise = false;
561 				}
562 				indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound, clockwise);
563 			}
564 			break;
565 		case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT:
566 			for (int j = i; j <= lastMatch; j++) {
567 				bool clockwise = true;
568 				if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
569 					clockwise = false;
570 				}
571 				indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16_le *)drawCalls[j].inds, indexLowerBound, clockwise);
572 			}
573 			break;
574 		case GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT:
575 			for (int j = i; j <= lastMatch; j++) {
576 				bool clockwise = true;
577 				if (gstate.isCullEnabled() && gstate.getCullMode() != drawCalls[j].cullMode) {
578 					clockwise = false;
579 				}
580 				indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u32_le *)drawCalls[j].inds, indexLowerBound, clockwise);
581 			}
582 			break;
583 		}
584 
585 		const int vertexCount = indexUpperBound - indexLowerBound + 1;
586 
587 		// This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes.
588 		if (decodedVerts + vertexCount > VERTEX_BUFFER_MAX) {
589 			return;
590 		}
591 
592 		// 3. Decode that range of vertex data.
593 		dec_->DecodeVerts(dest + decodedVerts * (int)dec_->GetDecVtxFmt().stride,
594 			dc.verts, indexLowerBound, indexUpperBound);
595 		decodedVerts += vertexCount;
596 
597 		// 4. Advance indexgen vertex counter.
598 		indexGen.Advance(vertexCount);
599 		i = lastMatch;
600 	}
601 }
602 
ComputeMiniHashRange(const void * ptr,size_t sz)603 inline u32 ComputeMiniHashRange(const void *ptr, size_t sz) {
604 	// Switch to u32 units, and round up to avoid unaligned accesses.
605 	// Probably doesn't matter if we skip the first few bytes in some cases.
606 	const u32 *p = (const u32 *)(((uintptr_t)ptr + 3) & ~3);
607 	sz >>= 2;
608 
609 	if (sz > 100) {
610 		size_t step = sz / 4;
611 		u32 hash = 0;
612 		for (size_t i = 0; i < sz; i += step) {
613 			hash += XXH3_64bits(p + i, 100);
614 		}
615 		return hash;
616 	} else {
617 		return p[0] + p[sz - 1];
618 	}
619 }
620 
ComputeMiniHash()621 u32 DrawEngineCommon::ComputeMiniHash() {
622 	u32 fullhash = 0;
623 	const int vertexSize = dec_->GetDecVtxFmt().stride;
624 	const int indexSize = IndexSize(dec_->VertexType());
625 
626 	int step;
627 	if (numDrawCalls < 3) {
628 		step = 1;
629 	} else if (numDrawCalls < 8) {
630 		step = 4;
631 	} else {
632 		step = numDrawCalls / 8;
633 	}
634 	for (int i = 0; i < numDrawCalls; i += step) {
635 		const DeferredDrawCall &dc = drawCalls[i];
636 		if (!dc.inds) {
637 			fullhash += ComputeMiniHashRange(dc.verts, vertexSize * dc.vertexCount);
638 		} else {
639 			int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound;
640 			fullhash += ComputeMiniHashRange((const u8 *)dc.verts + vertexSize * indexLowerBound, vertexSize * (indexUpperBound - indexLowerBound));
641 			fullhash += ComputeMiniHashRange(dc.inds, indexSize * dc.vertexCount);
642 		}
643 	}
644 
645 	return fullhash;
646 }
647 
ComputeHash()648 uint64_t DrawEngineCommon::ComputeHash() {
649 	uint64_t fullhash = 0;
650 	const int vertexSize = dec_->GetDecVtxFmt().stride;
651 	const int indexSize = IndexSize(dec_->VertexType());
652 
653 	// TODO: Add some caps both for numDrawCalls and num verts to check?
654 	// It is really very expensive to check all the vertex data so often.
655 	for (int i = 0; i < numDrawCalls; i++) {
656 		const DeferredDrawCall &dc = drawCalls[i];
657 		if (!dc.inds) {
658 			fullhash += XXH3_64bits((const char *)dc.verts, vertexSize * dc.vertexCount);
659 		} else {
660 			int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound;
661 			int j = i + 1;
662 			int lastMatch = i;
663 			while (j < numDrawCalls) {
664 				if (drawCalls[j].verts != dc.verts)
665 					break;
666 				indexLowerBound = std::min(indexLowerBound, (int)dc.indexLowerBound);
667 				indexUpperBound = std::max(indexUpperBound, (int)dc.indexUpperBound);
668 				lastMatch = j;
669 				j++;
670 			}
671 			// This could get seriously expensive with sparse indices. Need to combine hashing ranges the same way
672 			// we do when drawing.
673 			fullhash += XXH3_64bits((const char *)dc.verts + vertexSize * indexLowerBound,
674 				vertexSize * (indexUpperBound - indexLowerBound));
675 			// Hm, we will miss some indices when combining above, but meh, it should be fine.
676 			fullhash += XXH3_64bits((const char *)dc.inds, indexSize * dc.vertexCount);
677 			i = lastMatch;
678 		}
679 	}
680 
681 	fullhash += XXH3_64bits(&drawCalls[0].uvScale, sizeof(drawCalls[0].uvScale) * numDrawCalls);
682 	return fullhash;
683 }
684 
685 // vertTypeID is the vertex type but with the UVGen mode smashed into the top bits.
SubmitPrim(void * verts,void * inds,GEPrimitiveType prim,int vertexCount,u32 vertTypeID,int cullMode,int * bytesRead)686 void DrawEngineCommon::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead) {
687 	if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) {
688 		DispatchFlush();
689 	}
690 
691 	// TODO: Is this the right thing to do?
692 	if (prim == GE_PRIM_KEEP_PREVIOUS) {
693 		prim = prevPrim_ != GE_PRIM_INVALID ? prevPrim_ : GE_PRIM_POINTS;
694 	} else {
695 		prevPrim_ = prim;
696 	}
697 
698 	// If vtype has changed, setup the vertex decoder.
699 	if (vertTypeID != lastVType_) {
700 		dec_ = GetVertexDecoder(vertTypeID);
701 		lastVType_ = vertTypeID;
702 	}
703 
704 	*bytesRead = vertexCount * dec_->VertexSize();
705 
706 	// Check that we have enough vertices to form the requested primitive.
707 	if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES))
708 		return;
709 
710 	if (g_Config.bVertexCache) {
711 		u32 dhash = dcid_;
712 		dhash = __rotl(dhash ^ (u32)(uintptr_t)verts, 13);
713 		dhash = __rotl(dhash ^ (u32)(uintptr_t)inds, 13);
714 		dhash = __rotl(dhash ^ (u32)vertTypeID, 13);
715 		dhash = __rotl(dhash ^ (u32)vertexCount, 13);
716 		dcid_ = dhash ^ (u32)prim;
717 	}
718 
719 	DeferredDrawCall &dc = drawCalls[numDrawCalls];
720 	dc.verts = verts;
721 	dc.inds = inds;
722 	dc.indexType = (vertTypeID & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT;
723 	dc.prim = prim;
724 	dc.vertexCount = vertexCount;
725 	dc.uvScale = gstate_c.uv;
726 	dc.cullMode = cullMode;
727 
728 	if (inds) {
729 		GetIndexBounds(inds, vertexCount, vertTypeID, &dc.indexLowerBound, &dc.indexUpperBound);
730 	} else {
731 		dc.indexLowerBound = 0;
732 		dc.indexUpperBound = vertexCount - 1;
733 	}
734 
735 	numDrawCalls++;
736 	vertexCountInDrawCalls_ += vertexCount;
737 
738 	if (g_Config.bSoftwareSkinning && (vertTypeID & GE_VTYPE_WEIGHT_MASK)) {
739 		DecodeVertsStep(decoded, decodeCounter_, decodedVerts_);
740 		decodeCounter_++;
741 	}
742 
743 	if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) {
744 		// Rendertarget == texture? Shouldn't happen. Still, try some mitigations.
745 		gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
746 		DispatchFlush();
747 	}
748 }
749 
CanUseHardwareTransform(int prim)750 bool DrawEngineCommon::CanUseHardwareTransform(int prim) {
751 	if (!useHWTransform_)
752 		return false;
753 	return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
754 }
755 
CanUseHardwareTessellation(GEPatchPrimType prim)756 bool DrawEngineCommon::CanUseHardwareTessellation(GEPatchPrimType prim) {
757 	if (useHWTessellation_) {
758 		return CanUseHardwareTransform(PatchPrimToPrim(prim));
759 	}
760 	return false;
761 }
762 
CopyControlPoints(float * pos,float * tex,float * col,int posStride,int texStride,int colStride,const SimpleVertex * const * points,int size,u32 vertType)763 void TessellationDataTransfer::CopyControlPoints(float *pos, float *tex, float *col, int posStride, int texStride, int colStride, const SimpleVertex *const *points, int size, u32 vertType) {
764 	bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
765 	bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;
766 
767 	for (int i = 0; i < size; ++i) {
768 		memcpy(pos, points[i]->pos.AsArray(), 3 * sizeof(float));
769 		pos += posStride;
770 	}
771 	if (hasTexCoord) {
772 		for (int i = 0; i < size; ++i) {
773 			memcpy(tex, points[i]->uv, 2 * sizeof(float));
774 			tex += texStride;
775 		}
776 	}
777 	if (hasColor) {
778 		for (int i = 0; i < size; ++i) {
779 			memcpy(col, Vec4f::FromRGBA(points[i]->color_32).AsArray(), 4 * sizeof(float));
780 			col += colStride;
781 		}
782 	}
783 }
784