PS2GL
OpenGL*-like API for the PS2
Loading...
Searching...
No Matches
dlgmanager.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/math.h"
8#include "ps2s/packet.h"
9
10#include "ps2gl/dlgmanager.h"
11#include "ps2gl/dlist.h"
12#include "ps2gl/glcontext.h"
13#include "ps2gl/immgmanager.h"
14#include "ps2gl/lighting.h"
15#include "ps2gl/material.h"
16#include "ps2gl/renderer.h"
17#include "ps2gl/texture.h"
18
19using namespace ArrayType;
20
21/********************************************
22 * methods
23 */
24
25CDListGeomManager::CDListGeomManager(CGLContext& context)
26 : CGeomManager(context)
27 , CurDList(NULL)
28 , RendererMayHaveChanged(false)
29{
30}
31
32void CDListGeomManager::BeginDListDef()
33{
34 Prim = GL_INVALID_VALUE;
35 Geometry.Reset();
36
37 CDList& dlist = GLContext.GetDListManager().GetOpenDList();
38 CurDList = &dlist;
39
40 LastArrayAccessIsValid = false;
41}
42
43void CDListGeomManager::EndDListDef()
44{
45 Flush();
46
47 CurNormalBuf = NULL;
48 CurVertexBuf = NULL;
49 CurTexCoordBuf = NULL;
50 CurColorBuf = NULL;
51
52 CurDList = NULL;
53}
54
55void CDListGeomManager::Flush()
56{
57 if (Geometry.IsPending()) {
58 DrawBlock(Geometry);
59 Geometry.Reset();
60 }
61}
62
63/********************************************
64 * glBegin/glEnd
65 */
66
67void CDListGeomManager::BeginGeom(GLenum mode)
68{
69 if (Prim != mode)
70 PrimChanged(mode);
71
72 CDList& dlist = GLContext.GetDListManager().GetOpenDList();
73 CurNormalBuf = &dlist.GetNormalBuf();
74 CurVertexBuf = &dlist.GetVertexBuf();
75 CurTexCoordBuf = &dlist.GetTexCoordBuf();
76 CurColorBuf = &dlist.GetColorBuf();
77
78 Geometry.SetPrimType(mode);
79 Geometry.SetArrayType(kLinear);
80 Geometry.SetNormals(CurNormalBuf->GetNextPtr());
81 Geometry.SetVertices(CurVertexBuf->GetNextPtr());
82 Geometry.SetTexCoords(CurTexCoordBuf->GetNextPtr());
83 Geometry.SetColors(CurColorBuf->GetNextPtr());
84
85 InsideBeginEnd = true;
86}
87
88void CDListGeomManager::Vertex(cpu_vec_xyzw newVert)
89{
90 *CurVertexBuf += newVert;
91
92 Geometry.AddVertices();
93}
94
95class CSetNormalCmd : public CDListCmd {
96 cpu_vec_xyz Normal;
97
98public:
99 CSetNormalCmd(cpu_vec_xyz normal)
100 : Normal(normal)
101 {
102 }
103 CDListCmd* Play()
104 {
105 pGLContext->GetImmGeomManager().Normal(Normal);
106 return CDListCmd::GetNextCmd(this);
107 }
108};
109
110void CDListGeomManager::Normal(cpu_vec_xyz normal)
111{
112 if (DoNormalize)
113 normal.normalize();
114
115 if (InsideBeginEnd) {
116 CurNormal = normal;
117
118 *CurNormalBuf += normal(0);
119 *CurNormalBuf += normal(1);
120 *CurNormalBuf += normal(2);
121
122 Geometry.AddNormals();
123 } else {
124 // make sure we don't set this normal before any pending
125 // geometry that depends on the current normal (the one before
126 // setting this one)
127 Flush();
128 *CurDList += CSetNormalCmd(normal);
129 }
130}
131
132class CColorCmd : public CDListCmd {
133 cpu_vec_xyzw CurColor;
134
135public:
136 CColorCmd(cpu_vec_xyzw color)
137 : CurColor(color)
138 {
139 }
140 CDListCmd* Play()
141 {
142 pGLContext->GetMaterialManager().Color(CurColor);
143 return CDListCmd::GetNextCmd(this);
144 }
145};
146
147void CDListGeomManager::Color(cpu_vec_xyzw color)
148{
149 if (InsideBeginEnd) {
150 *CurColorBuf += color;
151
152 Geometry.AddColors();
153 } else {
154 CDList& dlist = GLContext.GetDListManager().GetOpenDList();
155 dlist += CColorCmd(color);
156 GLContext.CurMaterialChanged();
157 }
158}
159
161 float U, V;
162
163public:
164 CSetTexCoordCmd(float u, float v)
165 : U(u)
166 , V(v)
167 {
168 }
169 CDListCmd* Play()
170 {
171 pGLContext->GetImmGeomManager().TexCoord(U, V);
172 return CDListCmd::GetNextCmd(this);
173 }
174};
175
176void CDListGeomManager::TexCoord(float u, float v)
177{
178 if (InsideBeginEnd) {
179 CurTexCoord[0] = u;
180 CurTexCoord[1] = v;
181
182 *CurTexCoordBuf += u;
183 *CurTexCoordBuf += v;
184
185 Geometry.AddTexCoords();
186 } else {
187 Flush(); // see note for Normal
188 *CurDList += CSetTexCoordCmd(u, v);
189 }
190}
191
192void CDListGeomManager::EndGeom()
193{
194 InsideBeginEnd = false;
195
196 Geometry.SetWordsPerVertex(4);
197 Geometry.SetWordsPerNormal(3);
198 Geometry.SetWordsPerTexCoord(2);
199 Geometry.SetWordsPerColor(4);
200
201 Geometry.SetVerticesAreValid(true);
202
203 // if no normals were added use whatever the current normal is at list execution,
204 // if 1 normal was added, set that as the current normal,
205 // if more than one normal was added, assume there was one normal per vertex, and
206 // set the last to be the current normal
207 Geometry.SetNormalsAreValid(false);
208 if (Geometry.GetNumNewNormals() > 0) {
209 // make last normal current
210 *CurDList += CSetNormalCmd(CurNormal);
211
212 if (Geometry.GetNumNewNormals() > 1) {
213 mErrorIf(Geometry.GetNumNewVertices() != Geometry.GetNumNewNormals(),
214 "Sorry, but in display lists you need to specify either one normal, "
215 "or a normal for each vertex given.");
216 Geometry.SetNormalsAreValid(true);
217 }
218 }
219
220 // tex coord data
221 Geometry.SetTexCoordsAreValid(false);
222 if (Geometry.GetNumNewTexCoords() > 0) {
223 // make last tex coord current
224 *CurDList += CSetTexCoordCmd(CurTexCoord[0], CurTexCoord[1]);
225
226 mErrorIf(Geometry.GetNumNewVertices() != Geometry.GetNumNewTexCoords(),
227 "Sorry, but in display lists you need to specify either one "
228 "texture coord for each vertex given, or zero.");
229 Geometry.SetTexCoordsAreValid(true);
230 }
231
232 // colors
233 if (Geometry.GetNumNewColors() > 0) {
234 mErrorIf(Geometry.GetNumNewVertices() != Geometry.GetNumNewColors(),
235 "Sorry, but in display lists inside glBegin/glEnd you need "
236 "to specify either one color for each vertex given, or none.");
237 Geometry.SetColorsAreValid(true);
238 } else {
239 Geometry.SetColorsAreValid(false);
240 Geometry.SetColors(NULL);
241 }
242
243 CommitNewGeom();
244}
245
246/********************************************
247 * DrawArrays
248 */
249
250void CDListGeomManager::DrawArrays(GLenum mode, int first, int count)
251{
252 if (Prim != mode)
253 PrimChanged(mode);
254
255 Geometry.SetPrimType(mode);
256 Geometry.SetArrayType(kLinear);
257
258 Geometry.SetVertices(VertArray->GetVertices());
259 Geometry.SetNormals(VertArray->GetNormals());
260 Geometry.SetTexCoords(VertArray->GetTexCoords());
261 Geometry.SetColors(VertArray->GetColors());
262
263 Geometry.SetVerticesAreValid(VertArray->GetVerticesAreValid());
264 Geometry.SetNormalsAreValid(VertArray->GetNormalsAreValid());
265 Geometry.SetTexCoordsAreValid(VertArray->GetTexCoordsAreValid());
266 Geometry.SetColorsAreValid(VertArray->GetColorsAreValid());
267
268 Geometry.SetWordsPerVertex(VertArray->GetWordsPerVertex());
269 Geometry.SetWordsPerNormal(VertArray->GetWordsPerNormal());
270 Geometry.SetWordsPerTexCoord(VertArray->GetWordsPerTexCoord());
271 Geometry.SetWordsPerColor(VertArray->GetWordsPerColor());
272
273 Geometry.AddVertices(count);
274 Geometry.AddNormals(count);
275 Geometry.AddTexCoords(count);
276 Geometry.AddColors(count);
277
278 Geometry.AdjustNewGeomPtrs(first);
279
280 CommitNewGeom();
281}
282
283void CDListGeomManager::DrawIndexedArrays(GLenum primType,
284 int numIndices, const unsigned char* indices,
285 int numVertices)
286{
287 if (Prim != primType)
288 PrimChanged(primType);
289
290 Geometry.SetPrimType(primType);
291 Geometry.SetArrayType(kIndexed);
292
293 Geometry.SetVertices(VertArray->GetVertices());
294 Geometry.SetNormals(VertArray->GetNormals());
295 Geometry.SetTexCoords(VertArray->GetTexCoords());
296 Geometry.SetColors(VertArray->GetColors());
297
298 Geometry.SetVerticesAreValid(VertArray->GetVerticesAreValid());
299 Geometry.SetNormalsAreValid(VertArray->GetNormalsAreValid());
300 Geometry.SetTexCoordsAreValid(VertArray->GetTexCoordsAreValid());
301 Geometry.SetColorsAreValid(VertArray->GetColorsAreValid());
302
303 Geometry.SetWordsPerVertex(VertArray->GetWordsPerVertex());
304 Geometry.SetWordsPerNormal(VertArray->GetWordsPerNormal());
305 Geometry.SetWordsPerTexCoord(VertArray->GetWordsPerTexCoord());
306 Geometry.SetWordsPerColor(VertArray->GetWordsPerColor());
307
308 Geometry.AddVertices(numVertices);
309 Geometry.AddNormals(numVertices);
310 Geometry.AddTexCoords(numVertices);
311 Geometry.AddColors(numVertices);
312
313 Geometry.SetNumIndices(numIndices);
314 Geometry.SetIndices(indices);
315 Geometry.SetIStripLengths(NULL);
316
317 CommitNewGeom();
318}
319
320/********************************************
321 * methods / dlist commands that update state
322 */
323
325 GLenum PrimType;
326
327public:
328 CUpdateRendererContextCmd(GLenum type)
329 : PrimType(type)
330 {
331 }
332 CDListCmd* Play()
333 {
334 CImmGeomManager& gmanager = pGLContext->GetImmGeomManager();
335 gmanager.SyncRendererContext(PrimType);
336 return CDListCmd::GetNextCmd(this);
337 }
338};
339
340class CUpdatePrimCmd : public CDListCmd {
341 GLenum Prim;
342
343public:
344 CUpdatePrimCmd(GLenum prim)
345 : Prim(prim)
346 {
347 }
348 CDListCmd* Play()
349 {
350 pGLContext->GetImmGeomManager().GetRendererManager().PrimChanged(Prim);
351 return CDListCmd::GetNextCmd(this);
352 }
353};
354
355void CDListGeomManager::PrimChanged(GLenum prim)
356{
357 GLContext.PrimChanged();
358 GLContext.GetDListManager().GetOpenDList() += CUpdatePrimCmd(prim);
359}
360
362 bool PerVtxColors;
363 tArrayType ArrayType;
364
365public:
366 CUpdateRendererCmd(bool pvColors, tArrayType type)
367 : PerVtxColors(pvColors)
368 , ArrayType(type)
369 {
370 }
371 CDListCmd* Play()
372 {
373 CImmGeomManager& gmanager = pGLContext->GetImmGeomManager();
374 gmanager.SyncColorMaterial(PerVtxColors);
375 gmanager.SyncArrayType(ArrayType);
376 gmanager.SyncRenderer();
377 return CDListCmd::GetNextCmd(this);
378 }
379};
380
382public:
383 CDListCmd* Play()
384 {
385 pGLContext->GetImmGeomManager().SyncGsContext();
386 return CDListCmd::GetNextCmd(this);
387 }
388};
389
390/********************************************
391 * render-related methods/commands
392 */
393
394void CDListGeomManager::DrawingLinearArray()
395{
396 if (!LastArrayAccessIsValid || LastArrayAccessWasIndexed) {
397 GLContext.ArrayAccessChanged();
398 LastArrayAccessIsValid = true;
399 }
400 LastArrayAccessWasIndexed = false;
401}
402
403void CDListGeomManager::DrawingIndexedArray()
404{
405 if (!LastArrayAccessIsValid || !LastArrayAccessWasIndexed) {
406 GLContext.ArrayAccessChanged();
407 LastArrayAccessIsValid = true;
408 }
409 LastArrayAccessWasIndexed = true;
410}
411
412void CDListGeomManager::CommitNewGeom()
413{
414 // do this before updating the renderer
415 if (Geometry.GetNewArrayType() == kLinear)
416 DrawingLinearArray();
417 else
418 DrawingIndexedArray();
419
420 bool doReset = true;
421
422 if (Geometry.IsPending()) {
423 // if the context hasn't changed, try to merge the new geometry
424 // into the current block
425 if (GLContext.GetRendererContextChanged() == 0
426 && GLContext.GetGsContextChanged() == 0
427 && !UserRenderContextChanged
428 && GLContext.GetRendererPropsChanged() == 0
429 && Geometry.MergeNew())
430 doReset = false;
431 // couldn't merge; draw the old geometry so we can reset and start a new block
432 else {
433 DrawBlock(Geometry);
434 }
435 }
436
437 if (doReset) {
438 Geometry.MakeNewValuesCurrent();
439 Geometry.ResetNew(); // if we don't do this counts will keep accumulating
440
441 if (GLContext.GetRendererPropsChanged()) {
442 *CurDList += CUpdateRendererCmd(Geometry.GetColorsAreValid(), Geometry.GetArrayType());
443 GLContext.SetRendererPropsChanged(false);
444 GLContext.SetRendererContextChanged(true);
445 }
446 if (GLContext.GetRendererContextChanged()) {
447 *CurDList += CUpdateRendererContextCmd(Geometry.GetPrimType());
448 GLContext.SetRendererContextChanged(false);
449 Prim = Geometry.GetPrimType();
450 }
451 if (GLContext.GetGsContextChanged()) {
452 *CurDList += CUpdateGsContextCmd();
453 GLContext.SetGsContextChanged(false);
454 }
455 if (UserRenderContextChanged) {
456 // not much point in adding this into the dl since there's no way now of
457 // adding the user context change into the dl..
458 // might be useful to break things up, though..
459 UserRenderContextChanged = false;
460 }
461 }
462}
463
464class CDrawArraysCmd : public CDListCmd {
465 CGeometryBlock Geometry;
466 bool IsCached;
467 CDList& DList;
468 CVifSCDmaPacket* RenderPacket;
469 tU64 RenderContextDependencies, RenderContextDepMask;
470
471public:
472 CDrawArraysCmd(CGeometryBlock& block, CDList& dlist)
473 : Geometry(block)
474 , IsCached(false)
475 , DList(dlist)
476 , RenderPacket(NULL)
477 , RenderContextDependencies(0)
478 , RenderContextDepMask(0)
479 {
480 }
481
482 CDListCmd* Play()
483 {
484
485 // ** do not ** update the renderer context here; it will have
486 // been taken care of by other dlist commands
487
488 // first, check to see if the packet needs to be rebuilt. This decision
489 // is based on what the renderer tells us that it cares about. The
490 // default renderers, for example, will generate packets that embed
491 // whether texture mapping is enabled and so will need to be rebuilt if
492 // the packet is called in a context different from that in which it was
493 // first created.
494
495 tU64 curRenderContext = (tU64)pGLContext->GetImmGeomManager().GetRendererManager().GetRendererReqs();
496 tU64 curRenderContextDeps = curRenderContext & RenderContextDepMask;
497 bool rebuildPacket = (curRenderContextDeps != RenderContextDependencies);
498
499 // [re]build cached dma packet
500
501 if (!IsCached || rebuildPacket) {
502
503 // we need to build the packet to render this array
504
505 // first, can it be built once and reused?
506 CImmGeomManager& gmanager = pGLContext->GetImmGeomManager();
507 CRenderer& renderer = gmanager.GetRendererManager().GetCurRenderer();
508 bool cachePacket = renderer.GetCachePackets(Geometry);
509
510 // next, under what conditions does the packet we're about to build remain valid?
511 RenderContextDepMask = renderer.GetRenderContextDeps();
512 RenderContextDependencies = RenderContextDepMask & curRenderContext;
513
514 if (cachePacket) {
515 // allocate memory for the new packet
516
517 // ask the renderer how much memory to allocate for the packet
518 int qwords = renderer.GetPacketQwordSize(Geometry);
519
520 if (!RenderPacket) {
521 RenderPacket = new CVifSCDmaPacket(qwords, DMAC::Channels::vif1,
522 Packet::kXferTags,
523 Core::MemMappings::UncachedAccl);
524 DList.RegisterNewPacket(RenderPacket);
525 }
526
527 // if this is not the first time creating the packet, we need to
528 // delete the old packet, but not immediately
529 // because it may take up to two frames to be dma'ed
530 if (IsCached) {
531 void* newBuf = CDmaPacket::AllocBuffer(qwords,
532 Core::MemMappings::UncachedAccl);
533 void* oldBuf = RenderPacket->SwapOutBuffer(newBuf);
534 pGLContext->AddBufferToBeFreed(Core::MakePtrNormal(oldBuf));
535 }
536
537 RenderPacket->Reset();
538
539 IsCached = true;
540 } else {
541 // don't cache the packet.. use the main dma packet
542 RenderPacket = &pGLContext->GetVif1Packet();
543 }
544
545 pGLContext->PushVif1Packet();
546 {
547 pGLContext->SetVif1Packet(*RenderPacket);
548 renderer.DrawLinearArrays(Geometry);
549 }
550 pGLContext->PopVif1Packet();
551
552 // terminate cached packets with a Ret() so they can be Call()ed
553 if (cachePacket) {
554 RenderPacket->Ret();
555 RenderPacket->Pad128();
556 RenderPacket->CloseTag();
557 }
558 }
559
560 // if the packet was cached, call() it from the vif1 dma chain
561 if (IsCached) {
562 pGLContext->GetVif1Packet().Call(*RenderPacket);
563 pGLContext->GetVif1Packet().Pad128();
564 pGLContext->GetVif1Packet().CloseTag();
565 } else {
566 // not really necessary
567 RenderPacket = NULL;
568 }
569
570 return CDListCmd::GetNextCmd(this);
571 }
572};
573
575 CGeometryBlock Geometry;
576 bool IsCached;
577 CDList& DList;
578 CVifSCDmaPacket* RenderPacket;
579 bool IsTexEnabled, IsLightingEnabled;
580
581public:
583 : Geometry(block)
584 , IsCached(false)
585 , DList(dlist)
586 , RenderPacket(NULL)
587 , IsTexEnabled(false)
588 , IsLightingEnabled(false)
589 {
590 }
591
592 CDListCmd* Play()
593 {
594
595 // ** do not ** update the renderer context here; it will have
596 // been taken care by other dlist commands
597
598 bool texEnabled = pGLContext->GetTexManager().GetTexEnabled();
599 bool lEnabled = pGLContext->GetImmLighting().GetLightingEnabled();
600
601 // don't cache the packet if it depends on the current normal
602 bool dontCache = (lEnabled && !Geometry.GetNormalsAreValid());
603
604 // [re]build cached dma packet
605 if (!IsCached
606 || texEnabled != IsTexEnabled
607 || lEnabled != IsLightingEnabled) {
608
609 if (!dontCache) {
610
611 // allocate packet
612 if (!RenderPacket) {
613 // FIXME: this is a pitiful hack for allocating enough memory
614 // change below, too
615 int qwords = Math::Max(Geometry.GetNumArrays(), 1) * 100;
616 RenderPacket = new CVifSCDmaPacket(qwords, DMAC::Channels::vif1,
617 Packet::kXferTags,
618 Core::MemMappings::UncachedAccl);
619 DList.RegisterNewPacket(RenderPacket);
620 }
621
622 // if this is not the first time creating the packet, we need to
623 // delete the old packet, but not immediately
624 // because it may take up to two frames to be dma'ed
625 if (IsCached) {
626 int qwords = Math::Max(Geometry.GetNumArrays(), 1) * 100;
627 void* newBuf = CDmaPacket::AllocBuffer(qwords,
628 Core::MemMappings::UncachedAccl);
629 void* oldBuf = RenderPacket->SwapOutBuffer(newBuf);
630 pGLContext->AddBufferToBeFreed(oldBuf);
631 }
632
633 RenderPacket->Reset();
634
635 IsCached = true;
636 } else {
637 // don't cache the packet.. use the main dma packet
638 RenderPacket = &pGLContext->GetVif1Packet();
639 }
640
641 IsTexEnabled = texEnabled;
642 IsLightingEnabled = lEnabled;
643
644 pGLContext->PushVif1Packet();
645 {
646 pGLContext->SetVif1Packet(*RenderPacket);
647 CImmGeomManager& gmanager = pGLContext->GetImmGeomManager();
648 CRenderer& renderer = gmanager.GetRendererManager().GetCurRenderer();
649 renderer.DrawIndexedArrays(Geometry);
650 }
651 pGLContext->PopVif1Packet();
652
653 if (!dontCache) {
654 RenderPacket->Ret();
655 RenderPacket->Pad128();
656 RenderPacket->CloseTag();
657 }
658 }
659
660 if (!dontCache) {
661 pGLContext->GetVif1Packet().Call(*RenderPacket);
662 pGLContext->GetVif1Packet().Pad128();
663 pGLContext->GetVif1Packet().CloseTag();
664 } else {
665 RenderPacket = NULL;
666 }
667
668 return CDListCmd::GetNextCmd(this);
669 }
670};
671
672void CDListGeomManager::DrawBlock(CGeometryBlock& block)
673{
674 if (block.GetArrayType() == kLinear)
675 *CurDList += CDrawArraysCmd(block, *CurDList);
676 else
677 *CurDList += CDrawIndexedArraysCmd(block, *CurDList);
678}
679
681 tU64 Flag;
682
683public:
684 CEnableCustomCmd(tU64 flag)
685 : Flag(flag)
686 {
687 }
688 CDListCmd* Play()
689 {
690 pGLContext->GetImmGeomManager().GetRendererManager().EnableCustom(Flag);
691 return CDListCmd::GetNextCmd(this);
692 }
693};
694
695void CDListGeomManager::EnableCustom(tU64 flag)
696{
697 *CurDList += CEnableCustomCmd(flag);
698}
699
701 tU64 Flag;
702
703public:
704 CDisableCustomCmd(tU64 flag)
705 : Flag(flag)
706 {
707 }
708 CDListCmd* Play()
709 {
710 pGLContext->GetImmGeomManager().GetRendererManager().DisableCustom(Flag);
711 return CDListCmd::GetNextCmd(this);
712 }
713};
714
715void CDListGeomManager::DisableCustom(tU64 flag)
716{
717 *CurDList += CDisableCustomCmd(flag);
718}
void AddBufferToBeFreed(void *buf)
Definition glcontext.h:243
virtual bool GetCachePackets(const CGeometryBlock &geometry)=0
virtual void DrawIndexedArrays(CGeometryBlock &block)
Draw arrays of vertices that are accessed by index (i.e., glDrawElements)
Definition renderer.h:130
virtual void DrawLinearArrays(CGeometryBlock &block)
Draw arrays of vertices that are accessed linearly (i.e., glDrawArrays)
Definition renderer.h:125
virtual int GetPacketQwordSize(const CGeometryBlock &geometry)=0
virtual CRendererProps GetRenderContextDeps()=0