PS2GL
OpenGL*-like API for the PS2
Loading...
Searching...
No Matches
base_renderer.cpp
1/* Copyright (C) 2000,2001,2002 Sony Computer Entertainment America
2
3 This file is subject to the terms and conditions of the GNU Lesser
4 General Public License Version 2.1. See the file "COPYING" in the
5 main directory of this archive for more details. */
6
7#include "ps2s/cpu_matrix.h"
8#include "ps2s/math.h"
9#include "ps2s/packet.h"
10
11#include <stdlib.h>
12
13#include "ps2gl/base_renderer.h"
14#include "ps2gl/drawcontext.h"
15#include "ps2gl/glcontext.h"
16#include "ps2gl/immgmanager.h"
17#include "ps2gl/lighting.h"
18#include "ps2gl/material.h"
19#include "ps2gl/matrix.h"
20#include "ps2gl/metrics.h"
21#include "ps2gl/texture.h"
22
23#include "vu1_context.h"
24
25void CBaseRenderer::GetUnpackAttribs(int numWords, unsigned int& mode, Vifs::tMask& mask)
26{
27
28 if (numWords == 3) {
29 Vifs::tMask vec3Mask = { 0, 0, 0, 1,
30 0, 0, 0, 1,
31 0, 0, 0, 1,
32 0, 0, 0, 1 };
33 mode = Vifs::UnpackModes::v3_32;
34 mask = vec3Mask;
35 } else if (numWords == 4) {
36 Vifs::tMask vec4Mask = { 0, 0, 0, 0,
37 0, 0, 0, 0,
38 0, 0, 0, 0,
39 0, 0, 0, 0 };
40 mode = Vifs::UnpackModes::v4_32;
41 mask = vec4Mask;
42 } else if (numWords == 2) {
43 Vifs::tMask vec2Mask = { 0, 0, 1, 1,
44 0, 0, 1, 1,
45 0, 0, 1, 1,
46 0, 0, 1, 1 };
47 mode = Vifs::UnpackModes::v2_32;
48 mask = vec2Mask;
49 } else {
50 mError("shouldn't get here (you're probably calling glDrawArrays"
51 "without setting one of the pointers)");
52 }
53}
54
60void CBaseRenderer::InitXferBlock(CVifSCDmaPacket& packet,
61 int wordsPerVertex, int wordsPerNormal,
62 int wordsPerTex, int wordsPerColor)
63{
64 CImmGeomManager& gmanager = pGLContext->GetImmGeomManager();
65
66 NormalBuf = &gmanager.GetNormalBuf();
67 TexCoordBuf = &gmanager.GetTexCoordBuf();
68
69 CurNormal = gmanager.GetCurNormal();
70 const float* texCoord = gmanager.GetCurTexCoord();
71 CurTexCoord[0] = texCoord[0];
72 CurTexCoord[1] = texCoord[1];
73
74 // get unpack modes/masks
75
76 WordsPerVertex = wordsPerVertex;
77 GetUnpackAttribs(WordsPerVertex, VertexUnpackMode, VertexUnpackMask);
78
79 WordsPerNormal = (wordsPerNormal > 0) ? wordsPerNormal : 3;
80 GetUnpackAttribs(WordsPerNormal, NormalUnpackMode, NormalUnpackMask);
81
82 WordsPerTexCoord = (wordsPerTex > 0) ? wordsPerTex : 2;
83 GetUnpackAttribs(WordsPerTexCoord, TexCoordUnpackMode, TexCoordUnpackMask);
84
85 WordsPerColor = (wordsPerColor > 0) ? wordsPerColor : 3;
86 GetUnpackAttribs(WordsPerColor, ColorUnpackMode, ColorUnpackMask);
87
88 // set up the row register to expand vectors with fewer than 4 elements
89
90 packet.Cnt();
91 {
92 // w is 256 to remind me that this is not used as the vertex w but
93 // is necessary to clear any adc bits set for strips, otherwise they
94 // accumulate..
95 static const float row[4] = { 0.0f, 0.0f, 1.0f, 256.0f };
96 packet.Strow(row);
97
98 packet.Pad128();
99 }
100 packet.CloseTag();
101}
102
114void CBaseRenderer::XferBlock(CVifSCDmaPacket& packet,
115 const void* vertices, const void* normals,
116 const void* texCoords, const void* colors,
117 int vu1Offset, int firstElement, int numToAdd)
118{
119 //
120 // vertices
121 //
122
123 if (XferVertices) {
124 mErrorIf(vertices == NULL, "Tried to render an array with no vertices!");
125 XferVectors(packet, (unsigned int*)vertices,
126 firstElement, numToAdd,
127 WordsPerVertex, VertexUnpackMask, VertexUnpackMode,
128 vu1Offset);
129 }
130
131 //
132 // normals
133 //
134
135 int firstNormal = firstElement;
136 if (XferNormals && normals == NULL) {
137 // no normals given, so use the current normal..
138 // I hate to actually write every normal into the packet,
139 // but I can't use the vif to expand the data because I
140 // need it to interleave the vertices, normals, etc..
141 CDmaPacket& normalBuf = *NormalBuf;
142 normals = (void*)normalBuf.GetNextPtr();
143 firstNormal = 0;
144
145 for (int i = 0; i < numToAdd; i++)
146 normalBuf += CurNormal;
147 }
148
149 if (XferNormals)
150 XferVectors(packet, (unsigned int*)normals,
151 firstNormal, numToAdd,
152 WordsPerNormal, NormalUnpackMask, NormalUnpackMode,
153 vu1Offset + 1);
154
155 //
156 // tex coords
157 //
158
159 int firstTexCoord = firstElement;
160 if (XferTexCoords && texCoords == NULL) {
161 // no tex coords given, so use the current value..
162 // see note above for normals
163 CDmaPacket& texCoordBuf = *TexCoordBuf;
164 texCoords = (void*)texCoordBuf.GetNextPtr();
165 firstTexCoord = 0;
166
167 for (int i = 0; i < numToAdd; i++) {
168 texCoordBuf += CurTexCoord[0];
169 texCoordBuf += CurTexCoord[1];
170 }
171 }
172 if (XferTexCoords)
173 XferVectors(packet, (unsigned int*)texCoords,
174 firstTexCoord, numToAdd,
175 WordsPerTexCoord, TexCoordUnpackMask, TexCoordUnpackMode,
176 vu1Offset + 2);
177
178 //
179 // colors
180 //
181
182 int firstColor = firstElement;
183 if (colors != NULL && XferColors) {
184 XferVectors(packet, (unsigned int*)colors,
185 firstColor, numToAdd,
186 WordsPerColor, ColorUnpackMask, ColorUnpackMode,
187 vu1Offset + 3);
188 }
189}
190
191#define kContextStart 0 // for the kLightBase stuff below
192
193void CBaseRenderer::AddVu1RendererContext(CVifSCDmaPacket& packet, GLenum primType, int vu1Offset)
194{
195 CGLContext& glContext = *pGLContext;
196
197 packet.Stcycl(1, 1);
198 packet.Flush();
199 packet.Pad96();
200 packet.OpenUnpack(Vifs::UnpackModes::v4_32, vu1Offset, Packet::kSingleBuff);
201 {
202 // find light pointers
203 CImmLighting& lighting = glContext.GetImmLighting();
204 tLightPtrs lightPtrs[8];
205 tLightPtrs *nextDir, *nextPt, *nextSpot;
206 nextDir = nextPt = nextSpot = &lightPtrs[0];
207 int numDirs, numPts, numSpots;
208 numDirs = numPts = numSpots = 0;
209 for (int i = 0; i < 8; i++) {
210 CImmLight& light = lighting.GetImmLight(i);
211 if (light.IsEnabled()) {
212 int lightBase = kLight0Base + vu1Offset;
213 if (light.IsDirectional()) {
214 nextDir->dir = lightBase + i * kLightStructSize;
215 nextDir++;
216 numDirs++;
217 } else if (light.IsPoint()) {
218 nextPt->point = lightBase + i * kLightStructSize;
219 nextPt++;
220 numPts++;
221 } else if (light.IsSpot()) {
222 nextSpot->spot = lightBase + i * kLightStructSize;
223 nextSpot++;
224 numSpots++;
225 }
226 }
227 }
228
229 bool doLighting = glContext.GetImmLighting().GetLightingEnabled();
230
231 // transpose of object to world space xfrm (for light directions)
232 cpu_mat_44 objToWorldXfrmTrans = glContext.GetModelViewStack().GetTop();
233 // clear any translations.. should be doing a 3x3 transpose..
234 objToWorldXfrmTrans.set_col3(cpu_vec_xyzw(0, 0, 0, 1));
235 objToWorldXfrmTrans = objToWorldXfrmTrans.transpose();
236 // do we need to rescale normals?
237 cpu_mat_44 normalRescale;
238 normalRescale.set_identity();
239 float normalScale = 1.0f;
240 CImmDrawContext& drawContext = glContext.GetImmDrawContext();
241 if (drawContext.GetRescaleNormals()) {
242 cpu_vec_xyzw fake_normal(1, 0, 0, 0);
243 fake_normal = objToWorldXfrmTrans * fake_normal;
244 normalScale = 1.0f / fake_normal.length();
245 normalRescale.set_scale(cpu_vec_xyz(normalScale, normalScale, normalScale));
246 }
247 objToWorldXfrmTrans = normalRescale * objToWorldXfrmTrans;
248
249 // num lights
250 if (doLighting) {
251 packet += numDirs;
252 packet += numPts;
253 packet += numSpots;
254 } else {
255 packet += (tU64)0;
256 packet += 0;
257 }
258
259 // backface culling multiplier -- this is 1.0f or -1.0f, the 6th bit
260 // also turns on/off culling
261 float bfc_mult = (float)drawContext.GetCullFaceDir();
262 unsigned int bfc_word;
263 asm(" ## nop ## "
264 : "=r"(bfc_word)
265 : "0"(bfc_mult));
266 bool do_culling = drawContext.GetDoCullFace() && (primType > GL_LINE_STRIP);
267 packet += bfc_word | (unsigned int)do_culling << 5;
268
269 // light pointers
270 packet.Add(&lightPtrs[0], 8);
271
272 float maxColorValue = GetMaxColorValue(glContext.GetTexManager().GetTexEnabled());
273
274 // add light info
275 for (int i = 0; i < 8; i++) {
276 CImmLight& light = lighting.GetImmLight(i);
277 packet += light.GetAmbient() * maxColorValue;
278 packet += light.GetDiffuse() * maxColorValue;
279 packet += light.GetSpecular() * maxColorValue;
280
281 if (light.IsDirectional())
282 packet += light.GetPosition();
283 else {
284 packet += light.GetPosition();
285 }
286
287 packet += light.GetSpotDir();
288
289 // attenuation coeffs for positional light sources
290 // because we're doing lighting calculations in object space,
291 // we need to adjust the attenuation of positional light sources
292 // and all lighting directions to take into account scaling
293 packet += light.GetConstantAtten();
294 packet += light.GetLinearAtten() * 1.0f / normalScale;
295 packet += light.GetQuadAtten() * 1.0f / normalScale;
296 packet += 0; // padding
297 }
298
299 // global ambient
300 cpu_vec_4 globalAmb;
301 if (doLighting)
302 globalAmb = lighting.GetGlobalAmbient() * maxColorValue;
303 else
304 globalAmb = cpu_vec_4(0, 0, 0, 0);
305 packet.Add((tU32*)&globalAmb, 3);
306
307 // stick in the offset to convert clip space depth value to GS
308 float depthClipToGs = (float)((1 << drawContext.GetDepthBits()) - 1) / 2.0f;
309 packet += depthClipToGs;
310
311 // cur material
312
313 CImmMaterial& material = glContext.GetMaterialManager().GetImmMaterial();
314
315 // add emissive component
316 cpu_vec_4 emission;
317 if (doLighting)
318 emission = material.GetEmission() * maxColorValue;
319 else
320 emission = glContext.GetMaterialManager().GetCurColor() * maxColorValue;
321 packet += emission;
322
323 // ambient
324 packet += material.GetAmbient();
325
326 // diffuse
327 cpu_vec_4 matDiffuse = material.GetDiffuse();
328 // the alpha value is set to the alpha of the diffuse in the renderers;
329 // this should be the current color alpha if lighting is disabled
330 if (!doLighting)
331 matDiffuse[3] = glContext.GetMaterialManager().GetCurColor()[3];
332 packet += matDiffuse;
333
334 // specular
335 packet += material.GetSpecular();
336
337 // vertex xform
338 packet += drawContext.GetVertexXform();
339
340 // fixed vertToEye vector for non-local specular
341 cpu_vec_xyzw vertToEye(0.0f, 0.0f, 1.0f, 0.0f);
342 packet += objToWorldXfrmTrans * vertToEye;
343
344 // transpose of object to world space transform
345 packet += objToWorldXfrmTrans;
346
347 // world to object space xfrm (for light positions)
348 cpu_mat_44 worldToObjXfrm = glContext.GetModelViewStack().GetInvTop();
349 packet += worldToObjXfrm;
350
351 // giftag - this is down at the bottom to make sure that when switching
352 // primitives the last buffer will have a chance to copy the giftag before
353 // it is overwritten with the new one
354 GLenum newPrimType = drawContext.GetPolygonMode();
355 if (newPrimType == GL_FILL)
356 newPrimType = primType;
357 newPrimType &= 0xff;
358 tGifTag giftag = BuildGiftag(newPrimType);
359 packet += giftag;
360
361 // add info used by clipping code
362 // first the dimensions of the framebuffer
363 float xClip = (float)2048.0f / (drawContext.GetFBWidth() * 0.5f * 2.0f);
364 packet += Math::Max(xClip, 1.0f);
365 float yClip = (float)2048.0f / (drawContext.GetFBHeight() * 0.5f * 2.0f);
366 packet += Math::Max(yClip, 1.0f);
367 float depthClip = 2048.0f / depthClipToGs;
368 // FIXME: maybe these 2048's should be 2047.5s...
369 depthClip *= 1.003f; // round up a bit for fp error (????)
370 packet += depthClip;
371 // enable/disable clipping
372 packet += (drawContext.GetDoClipping()) ? 1 : 0;
373 }
374 packet.CloseUnpack();
375}
376
377tGifTag
378CBaseRenderer::BuildGiftag(GLenum primType)
379{
380 CGLContext& glContext = *pGLContext;
381
382 primType &= 0x7; // convert from GL #define to gs prim number
383 CImmDrawContext& drawContext = glContext.GetImmDrawContext();
384 bool smoothShading = drawContext.GetDoSmoothShading();
385 bool useTexture = glContext.GetTexManager().GetTexEnabled();
386 bool alpha = drawContext.GetBlendEnabled();
387 unsigned int nreg = OutputQuadsPerVert;
388
389 GS::tPrim prim = { prim_type : primType, iip : smoothShading, tme : useTexture, fge : 0, abe : alpha, aa1 : 0, fst : 0, ctxt : 0, fix : 0 };
390 tGifTag giftag = { NLOOP : 0, EOP : 1, pad0 : 0, id : 0, PRE : 1, PRIM : *(tU64*)&prim, FLG : 0, NREG : nreg, REGS0 : 2, REGS1 : 1, REGS2 : 4 };
391 return giftag;
392}
393
394void CBaseRenderer::CacheRendererState()
395{
396 XferNormals = pGLContext->GetImmLighting().GetLightingEnabled();
397 XferTexCoords = pGLContext->GetTexManager().GetTexEnabled();
398 XferColors = pGLContext->GetMaterialManager().GetColorMaterialEnabled();
399}
400
402{
403 unsigned int size64 = MicrocodePacketSize / 8;
404 CVifSCDmaPacket& packet = pGLContext->GetVif1Packet();
405 const u64* code = (const u64*)MicrocodePacket;
406 unsigned int addr64 = 0;
407
408 mErrorIf((unsigned int)code & 0xf, "code not & 0xf");
409 mErrorIf(MicrocodePacketSize & 0xf, "size not & 0xf");
410
411 while (size64 > 0) {
412 // Total send size
413 unsigned int sendSize64 = (size64 > 256) ? 256 : size64;
414
415 // Add send code command (VIF_CMD_MPG)
416 packet.Ref(code, sendSize64 / 2);
417 packet.Pad96();
418 packet.Mpg(sendSize64 & 0xff, addr64);
419
420 code += sendSize64;
421 size64 -= sendSize64;
422 addr64 += sendSize64;
423 }
424 packet.Cnt();
425 packet.Mscal(0);
426 packet.Pad128();
427 packet.CloseTag();
428
429 pglAddToMetric(kMetricsRendererUpload);
430}
431
432void CBaseRenderer::XferVectors(CVifSCDmaPacket& packet, unsigned int* dataStart,
433 int startOffset, int numVectors, int wordsPerVec,
434 Vifs::tMask unpackMask, tU32 unpackMode,
435 int vu1MemOffset)
436{
437 // find number of words to prepend with a cnt
438
439 unsigned int* vecDataStart = dataStart + startOffset * wordsPerVec;
440 unsigned int* vecDataEnd = vecDataStart + numVectors * wordsPerVec;
441
442 mAssert(numVectors > 0);
443 mErrorIf((unsigned int)vecDataStart & (4 - 1),
444 "XferVectors only works with word-aligned data");
445
446 int numWordsToPrepend = 0;
447 unsigned int* refXferStart = vecDataStart;
448 while ((unsigned int)refXferStart & (16 - 1)) {
449 numWordsToPrepend++;
450 refXferStart++;
451 if (refXferStart == vecDataEnd)
452 break;
453 }
454 int numWordsToAppend = 0;
455 unsigned int* refXferEnd = vecDataEnd;
456 while (((unsigned int)refXferEnd & (16 - 1)) && refXferEnd > refXferStart) {
457 numWordsToAppend++;
458 refXferEnd--;
459 }
460 int numQuadsInRefXfer = ((unsigned int)refXferEnd - (unsigned int)refXferStart) / 16;
461
462 packet.Cnt();
463 {
464 // set mask to expand vectors appropriately
465 packet.Stmask(unpackMask);
466
467 // prepend
468 if (numWordsToPrepend > 1) {
469 // either 2 or 3 words to prepend
470 packet.Nop().Nop();
471 if (numWordsToPrepend == 2)
472 packet.Nop();
473
474 packet.OpenUnpack(unpackMode,
475 vu1MemOffset,
476 VifDoubleBuffered,
477 Packet::kMasked);
478 packet.CloseUnpack(numVectors);
479
480 if (numWordsToPrepend == 3)
481 packet += *vecDataStart;
482 }
483
484 packet.Pad128();
485 }
486 packet.CloseTag();
487
488 // xfer qword block of vectors
489 packet.Ref(Core::MakePtrNormal(refXferStart), numQuadsInRefXfer);
490 {
491 // either 0 words to prepend or 1 word left to prepend
492 if (numWordsToPrepend == 0)
493 packet.Nop();
494 if (numWordsToPrepend <= 1) {
495 packet.OpenUnpack(unpackMode,
496 vu1MemOffset,
497 VifDoubleBuffered,
498 Packet::kMasked);
499 packet.CloseUnpack(numVectors);
500 }
501 if (numWordsToPrepend == 1)
502 packet += *vecDataStart;
503 else if (numWordsToPrepend == 2)
504 packet.Add(vecDataStart, 2);
505 else if (numWordsToPrepend == 3)
506 packet.Add(&vecDataStart[1], 2);
507 }
508
509 // xfer any remaining vectors
510 if (numWordsToAppend > 0) {
511 packet.Cnt();
512 {
513 packet.Add(refXferEnd, numWordsToAppend);
514 packet.Pad128();
515 }
516 packet.CloseTag();
517 }
518}
void XferBlock(CVifSCDmaPacket &packet, const void *vertices, const void *normals, const void *texCoords, const void *colors, int vu1Offset, int firstElement, int numToAdd)
virtual void Load()
Load the renderer into vu0/vu1 memory.
void InitXferBlock(CVifSCDmaPacket &packet, int wordsPerVertex, int wordsPerNormal, int wordsPerTex, int wordsPerColor)