PS2GL
OpenGL*-like API for the PS2
Loading...
Searching...
No Matches
glcontext.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 <string.h>
8
9#include "dma.h"
10#include "graph.h"
11#include "kernel.h"
12
13#include "GL/ps2gl.h"
14
15#include "ps2s/displayenv.h"
16#include "ps2s/drawenv.h"
17#include "ps2s/gsmem.h"
18#include "ps2s/math.h"
19#include "ps2s/packet.h"
20#include "ps2s/ps2stuff.h"
21#include "ps2s/texture.h"
22#include "ps2s/types.h"
23
24#include "ps2gl/displaycontext.h"
25#include "ps2gl/dlgmanager.h"
26#include "ps2gl/dlist.h"
27#include "ps2gl/drawcontext.h"
28#include "ps2gl/glcontext.h"
29#include "ps2gl/gmanager.h"
30#include "ps2gl/immgmanager.h"
31#include "ps2gl/lighting.h"
32#include "ps2gl/material.h"
33#include "ps2gl/matrix.h"
34#include "ps2gl/texture.h"
35
36/********************************************
37 * globals
38 */
39
40/********************************************
41 * CGLContext
42 */
43
44// static members
45
46CVifSCDmaPacket *CGLContext::CurPacket, *CGLContext::LastPacket,
47 *CGLContext::Vif1Packet = NULL, *CGLContext::SavedVif1Packet = NULL,
48 *CGLContext::ImmVif1Packet;
49
51int CGLContext::ImmediateRenderingFinishedSemaId = -1;
52int CGLContext::VsyncSemaId = -1;
53
54CGLContext::tRenderingFinishedCallback CGLContext::RenderingFinishedCallback = NULL;
55
56CGLContext::CGLContext(int immBufferQwordSize, int immDrawBufferQwordSize)
57 : StateChangesArePushed(false)
58 , IsCurrentFieldEven(true)
59 , CurrentFrameNumber(0)
60 , CurBuffer(0)
61{
62 CurPacket = new CVifSCDmaPacket(kDmaPacketMaxQwordLength, DMAC::Channels::vif1,
63 Packet::kXferTags, Core::MemMappings::UncachedAccl);
64 LastPacket = new CVifSCDmaPacket(kDmaPacketMaxQwordLength, DMAC::Channels::vif1,
65 Packet::kXferTags, Core::MemMappings::UncachedAccl);
66 Vif1Packet = CurPacket;
67
68 ImmVif1Packet = new CVifSCDmaPacket(immDrawBufferQwordSize, DMAC::Channels::vif1,
69 Packet::kXferTags, Core::MemMappings::UncachedAccl);
70
71 CurDrawEnvPtrs = DrawEnvPtrs0;
72 LastDrawEnvPtrs = DrawEnvPtrs1;
73 NumCurDrawEnvPtrs = 0;
74 NumLastDrawEnvPtrs = 0;
75
76 ImmGManager = new CImmGeomManager(*this, immBufferQwordSize);
77 DListGManager = new CDListGeomManager(*this);
78 CurGManager = ImmGManager;
79
80 ProjectionMatStack = new CImmMatrixStack(*this);
81 ModelViewMatStack = new CImmMatrixStack(*this);
82 DListMatStack = new CDListMatrixStack(*this);
83 CurMatrixStack = ModelViewMatStack;
84 SavedCurMatStack = NULL;
85
86 ImmLighting = new CImmLighting(*this);
87 DListLighting = new CDListLighting(*this);
88 CurLighting = ImmLighting;
89 // defaults
90 CLight& light = ImmLighting->GetLight(0);
91 light.SetDiffuse(cpu_vec_xyzw(1.0f, 1.0f, 1.0f, 1.0f));
92 light.SetSpecular(cpu_vec_xyzw(1.0f, 1.0f, 1.0f, 1.0f));
93
94 MaterialManager = new CMaterialManager(*this);
95 DListManager = new CDListManager;
96 TexManager = new CTexManager(*this);
97
98 ImmDrawContext = new CImmDrawContext(*this);
99 DListDrawContext = new CDListDrawContext(*this);
100 CurDrawContext = ImmDrawContext;
101
102 DisplayContext = new CDisplayContext(*this);
103
104 SetRendererContextChanged(true);
105 SetGsContextChanged(true);
106 SetRendererPropsChanged(true);
107
108 // util
109 NumBuffersToBeFreed[0] = NumBuffersToBeFreed[1] = 0;
110
111 GS::Init();
112
113 // create a few semaphores
114
115 struct t_ee_sema newSemaphore = { 0, 1, 0 }; // but maxCount doesn't work?
116 VsyncSemaId = CreateSema(&newSemaphore);
117 RenderingFinishedSemaId = CreateSema(&newSemaphore);
118 ImmediateRenderingFinishedSemaId = CreateSema(&newSemaphore);
119 mErrorIf(VsyncSemaId == -1
120 || RenderingFinishedSemaId == -1
121 || ImmediateRenderingFinishedSemaId == -1,
122 "Failed to create ps2gl semaphores.");
123
124 // add an interrupt handler for gs "signal" exceptions
125
126 AddIntcHandler(INTC_GS, CGLContext::GsIntHandler, 0 /*first handler*/);
127 EnableIntc(INTC_GS);
128 // clear any signal/vsync exceptions and wait for the next
129 *(volatile unsigned int*)GS::ControlRegs::csr = 9;
130 // enable signal and vsync exceptions
131 *(volatile unsigned int*)GS::ControlRegs::imr = 0x7600;
132}
133
134CGLContext::~CGLContext()
135{
136 delete CurPacket;
137 delete LastPacket;
138
139 delete ImmGManager;
140 delete DListGManager;
141
142 delete ProjectionMatStack;
143 delete ModelViewMatStack;
144 delete DListMatStack;
145
146 delete ImmLighting;
147 delete DListLighting;
148
149 delete MaterialManager;
150 delete DListManager;
151 delete TexManager;
152
153 delete ImmDrawContext;
154 delete DListDrawContext;
155
156 delete DisplayContext;
157}
158
159/********************************************
160 * display lists
161 */
162
163void CGLContext::BeginDListDef(unsigned int listID, GLenum mode)
164{
165 DListManager->NewList(listID, mode);
166
167 PushStateChanges();
168
169 // not so sure about these two, but let's be cautious
170 SetRendererContextChanged(true);
171 SetGsContextChanged(true);
172 // definately need this to force an update - indexed/linear arrays
173 SetRendererPropsChanged(true);
174
175 MaterialManager->BeginDListDef();
176 TexManager->BeginDListDef();
177 DListGManager->BeginDListDef();
178
179 CurLighting = DListLighting;
180 CurGManager = DListGManager;
181 SavedCurMatStack = CurMatrixStack;
182 CurMatrixStack = DListMatStack;
183 CurDrawContext = DListDrawContext;
184}
185
186void CGLContext::EndDListDef()
187{
188 DListGManager->EndDListDef();
189 MaterialManager->EndDListDef();
190 TexManager->EndDListDef();
191
192 CurLighting = ImmLighting;
193 CurGManager = ImmGManager;
194 CurMatrixStack = SavedCurMatStack;
195 CurDrawContext = ImmDrawContext;
196
197 PopStateChanges();
198
199 DListManager->EndList();
200}
201
202/********************************************
203 * matrix mode
204 */
205
207 GLenum Mode;
208
209public:
210 CSetMatrixModeCmd(GLenum mode)
211 : Mode(mode)
212 {
213 }
214 CDListCmd* Play()
215 {
216 glMatrixMode(Mode);
217 return CDListCmd::GetNextCmd(this);
218 }
219};
220
221void CGLContext::SetMatrixMode(GLenum mode)
222{
223 if (InDListDef()) {
224 DListManager->GetOpenDList() += CSetMatrixModeCmd(mode);
225 } else {
226 switch (mode) {
227 case GL_MODELVIEW:
228 CurMatrixStack = ModelViewMatStack;
229 break;
230 case GL_PROJECTION:
231 CurMatrixStack = ProjectionMatStack;
232 break;
233 default:
234 mNotImplemented();
235 }
236 }
237}
238
239/********************************************
240 * immediate geometry
241 */
242
243void CGLContext::BeginImmediateGeometry()
244{
245 // mErrorIf( InDListDef == true,
246 // "pglBeginImmediateGeom can't be called in a display list definition." );
247
248 // flush any pending geometry
249 GetImmGeomManager().Flush();
250
251 PushVif1Packet();
252 SetVif1Packet(*ImmVif1Packet);
253
254 ImmVif1Packet->Reset();
255}
256
257void CGLContext::EndImmediateGeometry()
258{
259 mAssert(Vif1Packet == ImmVif1Packet);
260
261 EndVif1Packet(2);
262
263 PopVif1Packet();
264}
265
266void CGLContext::RenderImmediateGeometry()
267{
268 ImmVif1Packet->End();
269 ImmVif1Packet->Pad128();
270 ImmVif1Packet->CloseTag();
271
272 ImmVif1Packet->Send();
273}
274
275void CGLContext::FinishRenderingImmediateGeometry(bool forceImmediateStop)
276{
277 mWarnIf(forceImmediateStop, "Interrupting currently rendering dma chain not supported yet");
278 mNotImplemented();
279}
280
281/********************************************
282 * normal geometry
283 */
284
285void CGLContext::BeginGeometry()
286{
287 // reset packets that will be drawn to during this frame
288
289 CurPacket->Reset();
290}
291
292void CGLContext::EndGeometry()
293{
294 EndVif1Packet(1);
295}
296
297void CGLContext::EndVif1Packet(unsigned short signalNum)
298{
299 //printf("%s(%d)\n", __FUNCTION__, signalNum);
300
301 // flush any pending geometry
302 GetImmGeomManager().Flush();
303
304 // end current packet
305 // write our id to the signal register and trigger an
306 // exception on the core when this dma chain reaches the end
307
308 tGifTag giftag;
309 giftag.NLOOP = 1;
310 giftag.EOP = 1;
311 giftag.PRE = 0;
312 giftag.FLG = 0; // packed
313 giftag.NREG = 1;
314 giftag.REGS0 = 0xe; // a+d
315
316 Vif1Packet->End();
317 Vif1Packet->Flush();
318 Vif1Packet->OpenDirect();
319 {
320 *Vif1Packet += giftag;
321 *Vif1Packet += Ps2glSignalId | signalNum;
322 *Vif1Packet += (tU64)0x60; // signal
323 }
324 Vif1Packet->CloseDirect();
325 Vif1Packet->CloseTag();
326}
327
328void CGLContext::RenderGeometry()
329{
330 //printf("%s\n", __FUNCTION__);
331
332 // make sure the semaphore we'll signal on completion is zero now
333 while (PollSema(RenderingFinishedSemaId) != -1)
334 ;
335
336 LastPacket->Send();
337}
338
339int CGLContext::GsIntHandler(int cause)
340{
341 int ret = 0;
342
343 tU32 csr = *(volatile tU32*)GS::ControlRegs::csr;
344 // is this a signal interrupt?
345 if (csr & 1) {
346 // is it one of ours?
347 tU64 sigLblId = *(volatile tU64*)GS::ControlRegs::siglblid;
348 if ((tU16)(sigLblId >> 16) == GetPs2glSignalId()) {
349 switch (sigLblId & 0xffff) {
350 case 1:
351 iSignalSema(RenderingFinishedSemaId);
352 if (RenderingFinishedCallback != NULL)
353 RenderingFinishedCallback();
354 break;
355 case 2:
356 iSignalSema(ImmediateRenderingFinishedSemaId);
357 break;
358 default:
359 mError("Unknown signal");
360 }
361
362 // clear our signal id
363 sigLblId &= ~0xffffffff;
364 *(volatile tU64*)GS::ControlRegs::siglblid = sigLblId;
365 // clear the exception and wait for the next
366 *(volatile unsigned int*)GS::ControlRegs::csr = 1;
367
368 ret = -1; // don't call other handlers
369 }
370 }
371 // is this a vsync interrupt?
372 else if (csr & 8) {
373 iSignalSema(VsyncSemaId);
374 // clear the exception and wait for the next
375 *(volatile unsigned int*)GS::ControlRegs::csr = 8;
376 }
377
378 // I'm not entirely sure why this is necessary, but if I don't do
379 // it then framing out can cause the display thread to lock (I've
380 // only verified it frozen waiting on pglFinishRenderingGeometry().)
381 // The GS manual says that a second "signal" event occuring before
382 // the first is cleared causes the gs to stop drawing, and the second
383 // interrupt will not be raised until that interrupt (signal) is masked
384 // and then unmasked. Could something similar be true for gs events/
385 // interrupts in general? This needs to be here, not in the vsync branch.
386 if (ret == -1) {
387 *(volatile unsigned int*)GS::ControlRegs::imr = 0x7f00;
388 *(volatile unsigned int*)GS::ControlRegs::imr = 0x7600;
389 }
390
391 return ret;
392}
393
394void CGLContext::FinishRenderingGeometry(bool forceImmediateStop)
395{
396 //printf("%s(%d)\n", __FUNCTION__, forceImmediateStop);
397
398 mWarnIf(forceImmediateStop, "Interrupting currently rendering dma chain not supported yet");
399 WaitSema(RenderingFinishedSemaId);
400}
401
402void CGLContext::WaitForVSync()
403{
404 //printf("%s\n", __FUNCTION__);
405
406 // wait for beginning of v-sync
407 WaitSema(VsyncSemaId);
408 // sometimes if we miss a frame the semaphore gets incremented
409 // more than once (because maxCount is ignored?) which causes the next
410 // call to WaitForVSync to fall through immediately, which is kinda bad,
411 // so make sure the count is zero after waiting.
412 while (PollSema(VsyncSemaId) != -1)
413 ;
414 // sceGsSyncV(0);
415 tU32 csr = *(volatile tU32*)GS::ControlRegs::csr;
416 IsCurrentFieldEven = (bool)((csr >> 13) & 1);
417}
418
419void CGLContext::SwapBuffers()
420{
421 //printf("%s\n", __FUNCTION__);
422
423 // switch packet ptrs
424
425 CVifSCDmaPacket* tempPkt = CurPacket;
426 CurPacket = LastPacket;
427 LastPacket = tempPkt;
428 Vif1Packet = CurPacket;
429
430 // switch drawenv ptrs
431
432 void** tempDEPtrs = CurDrawEnvPtrs;
433 CurDrawEnvPtrs = LastDrawEnvPtrs;
434 LastDrawEnvPtrs = tempDEPtrs;
435 NumLastDrawEnvPtrs = NumCurDrawEnvPtrs;
436 NumCurDrawEnvPtrs = 0;
437
438 // tell some modules that it's time to flip
439
440 GetImmGeomManager().SwapBuffers();
441 GetDListManager().SwapBuffers();
442 GetDisplayContext().SwapBuffers();
443 GetImmDrawContext().SwapBuffers(IsCurrentFieldEven);
444
445 // free memory that was waiting til end of frame
446 FreeWaitingBuffersAndSwap();
447
448 CurrentFrameNumber++;
449}
450
451void CGLContext::FreeWaitingBuffersAndSwap()
452{
453 //printf("%s\n", __FUNCTION__);
454
455 CurBuffer = 1 - CurBuffer;
456
457 for (int i = 0; i < NumBuffersToBeFreed[CurBuffer]; i++) {
458 free(BuffersToBeFreed[CurBuffer][i]);
459 }
460
461 NumBuffersToBeFreed[CurBuffer] = 0;
462}
463
464/********************************************
465 * ps2gl C interface
466 */
467
469CGLContext* pGLContext = NULL;
470
495int pglInit(int immBufferVertexSize, int immDrawBufferQwordSize)
496{
497 ps2sInit();
498 pGLContext = new CGLContext(immBufferVertexSize, immDrawBufferQwordSize);
499
500 return true;
501}
502
508{
509 return (pGLContext != NULL);
510}
511
515void pglFinish(void)
516{
517 if (pGLContext)
518 delete pGLContext;
519 ps2sFinish();
520}
521
530{
531 dma_channel_wait(DMAC::Channels::vif1, 1000000);
532}
533
539{
540 pGLContext->WaitForVSync();
541}
542
550{
551 mErrorIf(pGLContext == NULL, "You need to call pglInit()");
552
553 pGLContext->SwapBuffers();
554}
555
562{
563 pGLContext->SetRenderingFinishedCallback(cb);
564}
565
566/********************************************
567 * immediate geometry
568 */
569
570void pglBeginImmediateGeometry(void)
571{
572 pGLContext->BeginImmediateGeometry();
573}
574void pglEndImmediateGeometry(void)
575{
576 pGLContext->EndImmediateGeometry();
577}
578void pglRenderImmediateGeometry(void)
579{
580 pGLContext->RenderImmediateGeometry();
581}
582void pglFinishRenderingImmediateGeometry(int forceImmediateStop)
583{
584 pGLContext->FinishRenderingImmediateGeometry((bool)forceImmediateStop);
585}
586
587/********************************************
588 * normal geometry
589 */
590
591void pglBeginGeometry(void)
592{
593 pGLContext->BeginGeometry();
594}
595void pglEndGeometry(void)
596{
597 pGLContext->EndGeometry();
598}
599void pglRenderGeometry(void)
600{
601 pGLContext->RenderGeometry();
602}
603void pglFinishRenderingGeometry(int forceImmediateStop)
604{
605 pGLContext->FinishRenderingGeometry((bool)forceImmediateStop);
606}
607
608/********************************************
609 * enable / disable
610 */
611
612void pglEnable(GLenum cap)
613{
614 switch (cap) {
615 case PGL_CLIPPING:
616 pGLContext->GetDrawContext().SetDoClipping(true);
617 break;
618 default:
619 mError("Unknown option passed to pglEnable()");
620 }
621}
622
623void pglDisable(GLenum cap)
624{
625 switch (cap) {
626 case PGL_CLIPPING:
627 pGLContext->GetDrawContext().SetDoClipping(false);
628 break;
629 default:
630 mError("Unknown option passed to pglDisable()");
631 }
632}
633
638/********************************************
639 * gl interface
640 */
641
642void glEnable(GLenum cap)
643{
644 GL_FUNC_DEBUG("%s(0x%x)\n", __FUNCTION__, cap);
645
646 CLighting& lighting = pGLContext->GetLighting();
647
648 switch (cap) {
649 case GL_LIGHT0:
650 case GL_LIGHT1:
651 case GL_LIGHT2:
652 case GL_LIGHT3:
653 case GL_LIGHT4:
654 case GL_LIGHT5:
655 case GL_LIGHT6:
656 case GL_LIGHT7:
657 lighting.GetLight(0x7 & cap).SetEnabled(true);
658 break;
659 case GL_LIGHTING:
660 lighting.SetLightingEnabled(true);
661 break;
662
663 case GL_BLEND:
664 pGLContext->GetDrawContext().SetBlendEnabled(true);
665 break;
666
667 case GL_COLOR_MATERIAL:
668 pGLContext->GetMaterialManager().SetUseColorMaterial(true);
669 break;
670 case GL_RESCALE_NORMAL:
671 pGLContext->GetDrawContext().SetRescaleNormals(true);
672 break;
673
674 case GL_TEXTURE_2D:
675 pGLContext->GetTexManager().SetTexEnabled(true);
676 break;
677
678 case GL_NORMALIZE:
679 pGLContext->GetGeomManager().SetDoNormalize(true);
680 break;
681
682 case GL_CULL_FACE:
683 pGLContext->GetDrawContext().SetDoCullFace(true);
684 break;
685
686 case GL_ALPHA_TEST:
687 pGLContext->GetDrawContext().SetAlphaTestEnabled(true);
688 break;
689
690 case GL_DEPTH_TEST:
691 pGLContext->GetDrawContext().SetDepthTestEnabled(true);
692 break;
693
694 default:
695 mNotImplemented();
696 break;
697 }
698}
699
700void glDisable(GLenum cap)
701{
702 GL_FUNC_DEBUG("%s(0x%x)\n", __FUNCTION__, cap);
703
704 switch (cap) {
705 case GL_LIGHT0:
706 case GL_LIGHT1:
707 case GL_LIGHT2:
708 case GL_LIGHT3:
709 case GL_LIGHT4:
710 case GL_LIGHT5:
711 case GL_LIGHT6:
712 case GL_LIGHT7:
713 pGLContext->GetLighting().GetLight(0x7 & cap).SetEnabled(false);
714 break;
715 case GL_LIGHTING:
716 pGLContext->GetLighting().SetLightingEnabled(false);
717 break;
718
719 case GL_BLEND:
720 pGLContext->GetDrawContext().SetBlendEnabled(false);
721 break;
722
723 case GL_COLOR_MATERIAL:
724 pGLContext->GetMaterialManager().SetUseColorMaterial(false);
725 break;
726 case GL_RESCALE_NORMAL:
727 pGLContext->GetDrawContext().SetRescaleNormals(false);
728 break;
729
730 case GL_TEXTURE_2D:
731 pGLContext->GetTexManager().SetTexEnabled(false);
732 break;
733
734 case GL_NORMALIZE:
735 pGLContext->GetGeomManager().SetDoNormalize(false);
736 break;
737
738 case GL_CULL_FACE:
739 pGLContext->GetDrawContext().SetDoCullFace(false);
740 break;
741
742 case GL_ALPHA_TEST:
743 pGLContext->GetDrawContext().SetAlphaTestEnabled(false);
744 break;
745
746 case GL_DEPTH_TEST:
747 pGLContext->GetDrawContext().SetDepthTestEnabled(false);
748 break;
749
750 default:
751 mNotImplemented();
752 }
753}
754
755void glHint(GLenum target, GLenum mode)
756{
757 GL_FUNC_DEBUG("%s(0x%x,0x%x)\n", __FUNCTION__, target, mode);
758
759 mNotImplemented();
760}
761
762void glGetFloatv(GLenum pname, GLfloat* params)
763{
764 GL_FUNC_DEBUG("%s(0x%x,...)\n", __FUNCTION__, pname);
765
766 switch (pname) {
767 case GL_MODELVIEW_MATRIX:
768 memcpy(params, &(pGLContext->GetModelViewStack().GetTop()), 16 * 4);
769 break;
770 case GL_PROJECTION_MATRIX:
771 memcpy(params, &(pGLContext->GetProjectionStack().GetTop()), 16 * 4);
772 break;
773 default:
774 mNotImplemented("pname %d", pname);
775 break;
776 }
777}
778
779void glGetIntegerv(GLenum pname, int* params)
780{
781 GL_FUNC_DEBUG("%s(0x%x,...)\n", __FUNCTION__, pname);
782
783 mNotImplemented();
784}
785
786GLenum glGetError(void)
787{
788 GL_FUNC_DEBUG("%s()\n", __FUNCTION__);
789
790 mWarn("glGetError does nothing");
791
792 return 0;
793}
794
795const GLubyte* glGetString(GLenum name)
796{
797 GL_FUNC_DEBUG("%s(0x%x)\n", __FUNCTION__, name);
798
799 mNotImplemented();
800 return (GLubyte*)"not implemented";
801}
static tU16 GetPs2glSignalId()
Definition glcontext.h:237
static int RenderingFinishedSemaId
Semaphores signaled by the gs int handler.
Definition glcontext.h:168
static const tU64 Ps2glSignalId
Definition glcontext.h:165
void pglSetRenderingFinishedCallback(void(*cb)(void))
void pglFinish(void)
void pglWaitForVU1(void)
void pglSwapBuffers(void)
int pglHasLibraryBeenInitted(void)
void pglWaitForVSync(void)
int pglInit(int immBufferVertexSize, int immDrawBufferQwordSize)