PS2GL
OpenGL*-like API for the PS2
Loading...
Searching...
No Matches
linear_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 "ps2gl/drawcontext.h"
12#include "ps2gl/glcontext.h"
13#include "ps2gl/immgmanager.h"
14#include "ps2gl/lighting.h"
15#include "ps2gl/linear_renderer.h"
16#include "ps2gl/material.h"
17#include "ps2gl/matrix.h"
18#include "ps2gl/metrics.h"
19#include "ps2gl/texture.h"
20
21#include "vu1_mem_linear.h"
22
24{
25 int wordsPerVert = block.GetWordsPerVertex();
26 int wordsPerNormal = (block.GetNormalsAreValid()) ? block.GetWordsPerNormal() : 0;
27 int wordsPerTex = (block.GetTexCoordsAreValid()) ? block.GetWordsPerTexCoord() : 0;
28 int wordsPerColor = (block.GetColorsAreValid()) ? block.GetWordsPerColor() : 0;
29
30 CVifSCDmaPacket& packet = pGLContext->GetVif1Packet();
31 InitXferBlock(packet, wordsPerVert, wordsPerNormal, wordsPerTex, wordsPerColor);
32
33 // get max number of vertices per vu1 buffer
34
35 // let's assume separate unpacks for vertices, normals, tex uvs..
36 int maxUnpackVerts = 256;
37 // max number of vertex data in vu1 memory
38 int vu1QuadsPerVert = InputQuadsPerVert;
39 int inputBufSize = InputGeomBufSize;
40 int maxVu1VertsPerBuffer = inputBufSize / vu1QuadsPerVert;
41 // max vertices per buffer
42 int maxVertsPerBuffer = Math::Min(maxUnpackVerts, maxVu1VertsPerBuffer);
43 maxVertsPerBuffer -= 3;
44 // make sure we don't end in the middle of a polygon
45 maxVertsPerBuffer -= maxVertsPerBuffer % block.GetNumVertsPerPrim();
46
47 // draw
48
49 DrawBlock(packet, block, maxVertsPerBuffer);
50}
51
52void CLinearRenderer::InitContext(GLenum primType, tU32 rcChanges, bool userRcChanged)
53{
54 CGLContext& glContext = *pGLContext;
55 CVifSCDmaPacket& packet = glContext.GetVif1Packet();
56
57 packet.Cnt();
58 {
59 AddVu1RendererContext(packet, primType, kContextStart);
60
61 packet.Mscal(0);
62 packet.Flushe();
63
64 packet.Base(kDoubleBufBase);
65 packet.Offset(kDoubleBufOffset);
66 }
67 packet.CloseTag();
68
69 CacheRendererState();
70}
71
73{
74 // FIXME: this is a pitiful hack for allocating enough memory
75 return Math::Max(geometry.GetTotalVertices() / 70, 1) * 1000;
76}
77
80{
81 CRendererProps deps;
82 deps = (tU64)0;
83 deps.Lighting = 1;
84 deps.Texture = 1;
85 deps.PerVtxMaterial = 1;
86
87 return deps;
88}
89
91{
92 return !(pGLContext->GetImmLighting().GetLightingEnabled()
93 && !geometry.GetNormalsAreValid());
94}
95
96void CLinearRenderer::DrawBlock(CVifSCDmaPacket& packet,
97 CGeometryBlock& block, int maxVertsPerBuffer)
98{
99 mErrorIf(block.GetWordsPerVertex() == 2, "2 word vertices not supported");
100
101 // interleave the vertices, normals, tex coords, and colors using
102 // "skipping write" vif mode on each block of data
103 // (clobbered in XferBufferHeader())
104 packet.Cnt();
105 {
106 packet.Stcycl(1, InputQuadsPerVert);
107 packet.Pad128();
108 }
109 packet.CloseTag();
110
111 // return;
112
113 //
114 // loop over the strips in this geometry block
115 //
116
117 int numVertsToRestart = block.GetNumVertsToRestartStrip();
118 bool stripsCanBeMerged = block.GetStripsCanBeMerged();
119
120 int numVertsXferred = 0;
121 int numStripsInBuffer = 0;
122 unsigned short stripOffsets[16];
123 bool haveContinued = false;
124 const void *normals, *vertices, *texCoords, *colors;
125 normals = vertices = texCoords = colors = NULL;
126 int vu1BufferOffset = 0, stripIndex = 0, vertsInBlock = 0;
127 // keep number of verts transferred in each full buffer in sync with
128 // FindNumBuffers() below
129 int adjMaxVertsPerBuffer = maxVertsPerBuffer - (Math::IsOdd(maxVertsPerBuffer - numVertsToRestart));
130 for (int curStrip = 0; curStrip < block.GetNumStrips(); curStrip++) {
131
132 // find the number of vu1 buffers this strip will take
133 int numVertsFirstBuffer, numVertsLastBuffer, numBuffers;
134 FindNumBuffers(block.GetStripLength(curStrip),
135 numVertsToRestart, numVertsXferred, maxVertsPerBuffer,
136 numVertsFirstBuffer, numVertsLastBuffer, numBuffers);
137
138 //
139 // loop over the buffers this strip will fill (usually one)
140 //
141
142 int numVertsThisBuffer;
143 int indexIntoStrip = 0;
144 int vu1QuadsPerVert = InputQuadsPerVert;
145 for (int curBuffer = 0;
146 curBuffer < numBuffers;
147 curBuffer++, indexIntoStrip += numVertsThisBuffer - numVertsToRestart) {
148
149 // how many verts in this vu1 buffer?
150 if (curBuffer == 0)
151 numVertsThisBuffer = numVertsFirstBuffer;
152 else if (curBuffer == numBuffers - 1)
153 numVertsThisBuffer = numVertsLastBuffer;
154 else
155 numVertsThisBuffer = adjMaxVertsPerBuffer;
156
157 // xfer the list of primitives
158
159 if (!haveContinued) {
160 vertices = (block.GetVerticesAreValid()) ? block.GetVertices(curStrip) : NULL;
161 normals = (block.GetNormalsAreValid()) ? block.GetNormals(curStrip) : NULL;
162 texCoords = (block.GetTexCoordsAreValid()) ? block.GetTexCoords(curStrip) : NULL;
163 colors = (block.GetColorsAreValid()) ? block.GetColors(curStrip) : NULL;
164 vu1BufferOffset = InputGeomOffset + numVertsXferred * vu1QuadsPerVert;
165 stripIndex = indexIntoStrip;
166 vertsInBlock = 0;
167 }
168
169 // we only want to transfer the geometry data if:
170 // - the next strip is not adjacent in memory to this one (indicated by
171 // CGeometryBlock::StripIsContinued) and so cannot be combined into
172 // one transfer
173 // - this strip spills over into the next buffer (so it must be split
174 // into more than one transfer)
175 if (!block.StripIsContinued(curStrip)
176 || curBuffer < numBuffers - 1) {
177 XferBlock(packet,
178 vertices, normals, texCoords, colors,
179 vu1BufferOffset,
180 stripIndex, vertsInBlock + numVertsThisBuffer);
181 haveContinued = false;
182 } else {
183 vertsInBlock += numVertsThisBuffer;
184 haveContinued = true;
185 }
186
187 stripOffsets[numStripsInBuffer++] = numVertsXferred;
188 mErrorIf(numStripsInBuffer > 16, "Too many strips in buffer.. this shouldn't happen");
189 numVertsXferred += numVertsThisBuffer;
190
191 // if there are more buffers in this strip, render this buffer
192 if (curBuffer < numBuffers - 1) {
193 FinishBuffer(packet, numVertsToRestart, numVertsXferred, vu1QuadsPerVert,
194 numStripsInBuffer, stripOffsets);
195 numStripsInBuffer = 0;
196 numVertsXferred = 0;
197 }
198
199 } // end buffer loop
200
201 // finish this buffer if:
202 // - strips of this prim type cannot be merged into a single buffer/giftag
203 // - there is too little free space left
204 // - we have filled the max number of strips per buffer
205 // - or this is the last strip
206
207 // test against 'numVertsToRestart + 1' because FindNumBuffers() might
208 // clip off one vert for backface culling
209 // (maybe this should be 'adjMaxVertsPerBuffer'?)
210 if (!stripsCanBeMerged
211 || ((maxVertsPerBuffer - numVertsXferred) <= numVertsToRestart + 1)
212 || numStripsInBuffer == 16
213 || (curStrip == block.GetNumStrips() - 1)) {
214 if (haveContinued) {
215 XferBlock(packet,
216 vertices, normals, texCoords, colors,
217 vu1BufferOffset,
218 stripIndex, vertsInBlock);
219 haveContinued = false;
220 }
221
222 FinishBuffer(packet, numVertsToRestart, numVertsXferred, vu1QuadsPerVert,
223 numStripsInBuffer, stripOffsets);
224 numStripsInBuffer = 0;
225 numVertsXferred = 0;
226 }
227
228 } // end strip loop
229}
230
231void CLinearRenderer::FinishBuffer(CVifSCDmaPacket& packet, int numVertsToBreakStrip,
232 int numVertsInBuffer, int vu1QuadsPerVert,
233 int numStripsInBuffer, unsigned short* stripOffsets)
234{
235 packet.Cnt();
236 {
237 // going to start a new buffer, so finish this one
238 // header (giftag, etc..)
239 XferBufferHeader(packet, numVertsToBreakStrip,
240 numVertsInBuffer,
241 numStripsInBuffer, stripOffsets);
242
243 packet.Mscnt();
244 packet.Pad128();
245 }
246 packet.CloseTag();
247}
248
249void CLinearRenderer::FindNumBuffers(int numToAdd, int numVertsToRestart,
250 int numVertsAlreadyInFirstBuffer, int maxVertsPerBuffer,
251 int& numVertsFirstBuffer, int& numVertsLastBuffer,
252 int& numBuffers)
253{
254 // find number of buffers (chunks that will fit into vu1 mem buffers/unpack)
255
256 // deal with the first buffer
257 int numLeftToAdd;
258 int freeVertsFirstBuffer = maxVertsPerBuffer - numVertsAlreadyInFirstBuffer;
259 if (numToAdd <= freeVertsFirstBuffer) {
260 numVertsFirstBuffer = numToAdd;
261 numLeftToAdd = 0;
262 } else {
263 // we only want even numbers of vertices in tri strips that are spilled
264 // across buffer boundaries so that the sense of the backfacing calculation
265 // remains correct in the next buffer
266 numVertsFirstBuffer = freeVertsFirstBuffer - (int)Math::IsOdd(freeVertsFirstBuffer);
267 numLeftToAdd = numToAdd - (numVertsFirstBuffer - numVertsToRestart);
268 }
269 // if this doesn't make sense, try drawing it..
270 int adjVertsPerBuffer = maxVertsPerBuffer - numVertsToRestart;
271 adjVertsPerBuffer -= (int)Math::IsOdd(adjVertsPerBuffer);
272 numBuffers = 1 + numLeftToAdd / adjVertsPerBuffer; // 1 is first buffer
273 if (numLeftToAdd % adjVertsPerBuffer > numVertsToRestart)
274 numBuffers++;
275
276 numVertsLastBuffer = (numBuffers > 1)
277 ? numToAdd - ((numVertsFirstBuffer - numVertsToRestart)
278 + (numBuffers - 2) * adjVertsPerBuffer)
279 : numToAdd;
280}
281
282void CLinearRenderer::XferBufferHeader(CVifSCDmaPacket& packet,
283 int numVertsToBreakStrip,
284 int numVerts,
285 int numStripsInBuffer, unsigned short* stripOffsets)
286{
287 int vu1OutQuadsPerVert = OutputQuadsPerVert;
288
289 // xfer header info for strip
290 packet.Stcycl(4, 4);
291 packet.OpenUnpack(Vifs::UnpackModes::v4_32, 0, Packet::kDoubleBuff);
292 {
293 // num vertices
294 packet += numVerts;
295 packet += 0;
296 packet += (tU64)0;
297
298 // adc bits for the beginning of strips.. 16 24-bit values of following format:
299 // bits 0-9 : offset into output geometry (not including giftag)
300 // bit 10 : stop bit
301 // bit 11 : ADC bit of second vertex starting at offset
302 // these are converted to floats to do a right shift with a fp add on vu1
303 unsigned int adcBits = 0;
304 if (numVertsToBreakStrip == 0)
305 numStripsInBuffer = 0;
306 else if (numVertsToBreakStrip == 2)
307 adcBits = 0x800;
308
309 float adc;
310 unsigned int stopBit = 0x400;
311 for (int i = 0; i < 16; i++) {
312 if (i < numStripsInBuffer)
313 adc = (float)(adcBits | (unsigned int)stripOffsets[i] * vu1OutQuadsPerVert);
314 else if (i == numStripsInBuffer)
315 adc = (float)stopBit;
316 else
317 adc = (float)0;
318 packet += adc;
319 }
320 }
321 packet.CloseUnpack();
322
323 // restore the write cycle
324 packet.Stcycl(1, InputQuadsPerVert);
325}
void XferBlock(CVifSCDmaPacket &packet, const void *vertices, const void *normals, const void *texCoords, const void *colors, int vu1Offset, int firstElement, int numToAdd)
void InitXferBlock(CVifSCDmaPacket &packet, int wordsPerVertex, int wordsPerNormal, int wordsPerTex, int wordsPerColor)
int GetNumVertsToRestartStrip()
Definition gblock.h:173
virtual void InitContext(GLenum primType, tU32 rcChanges, bool userRcChanged)
virtual int GetPacketQwordSize(const CGeometryBlock &geometry)
virtual CRendererProps GetRenderContextDeps()
virtual bool GetCachePackets(const CGeometryBlock &geometry)
virtual void DrawLinearArrays(CGeometryBlock &block)
Draw arrays of vertices that are accessed linearly (i.e., glDrawArrays)