blob: 6ad2be34f5276d6bc7afd51b06b169248bf77cb6 [file] [log] [blame]
John Bauman89401822014-05-06 15:04:28 -04001// SwiftShader Software Renderer
2//
John Bauman19bac1e2014-05-06 15:23:49 -04003// Copyright(c) 2005-2012 TransGaming Inc.
John Bauman89401822014-05-06 15:04:28 -04004//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12#include "Renderer.hpp"
13
14#include "Clipper.hpp"
15#include "Math.hpp"
16#include "FrameBuffer.hpp"
17#include "Timer.hpp"
18#include "Surface.hpp"
19#include "Half.hpp"
20#include "Primitive.hpp"
21#include "Polygon.hpp"
22#include "SwiftConfig.hpp"
23#include "MutexLock.hpp"
24#include "CPUID.hpp"
25#include "Memory.hpp"
26#include "Resource.hpp"
27#include "Constants.hpp"
28#include "Debug.hpp"
John Bauman19bac1e2014-05-06 15:23:49 -040029#include "Reactor/Reactor.hpp"
John Bauman89401822014-05-06 15:04:28 -040030
John Bauman89401822014-05-06 15:04:28 -040031#undef max
32
John Bauman19bac1e2014-05-06 15:23:49 -040033bool disableServer = true;
John Bauman89401822014-05-06 15:04:28 -040034
35#ifndef NDEBUG
36unsigned int minPrimitives = 1;
37unsigned int maxPrimitives = 1 << 21;
38#endif
39
40namespace sw
41{
John Bauman19bac1e2014-05-06 15:23:49 -040042 extern bool halfIntegerCoordinates; // Pixel centers are not at integer coordinates
43 extern bool symmetricNormalizedDepth; // [-1, 1] instead of [0, 1]
44 extern bool booleanFaceRegister;
45 extern bool fullPixelPositionRegister;
Nicolas Capens44ffb652015-08-04 16:11:24 -040046 extern bool leadingVertexFirst; // Flat shading uses first vertex, else last
47 extern bool secondaryColor; // Specular lighting is applied after texturing
John Bauman19bac1e2014-05-06 15:23:49 -040048
John Bauman89401822014-05-06 15:04:28 -040049 extern bool forceWindowed;
50 extern bool complementaryDepthBuffer;
51 extern bool postBlendSRGB;
52 extern bool exactColorRounding;
Nicolas Capensa0f4be82014-10-22 14:35:30 -040053 extern TransparencyAntialiasing transparencyAntialiasing;
John Bauman89401822014-05-06 15:04:28 -040054 extern bool forceClearRegisters;
55
John Bauman66b8ab22014-05-06 15:57:45 -040056 extern bool precacheVertex;
57 extern bool precacheSetup;
58 extern bool precachePixel;
59
John Bauman89401822014-05-06 15:04:28 -040060 int batchSize = 128;
61 int threadCount = 1;
62 int unitCount = 1;
63 int clusterCount = 1;
64
John Bauman19bac1e2014-05-06 15:23:49 -040065 TranscendentalPrecision logPrecision = ACCURATE;
66 TranscendentalPrecision expPrecision = ACCURATE;
67 TranscendentalPrecision rcpPrecision = ACCURATE;
68 TranscendentalPrecision rsqPrecision = ACCURATE;
69 bool perspectiveCorrection = true;
70
John Bauman89401822014-05-06 15:04:28 -040071 struct Parameters
72 {
73 Renderer *renderer;
74 int threadIndex;
75 };
76
77 DrawCall::DrawCall()
78 {
79 queries = 0;
80
Alexis Hetu04c967a2015-07-08 15:56:17 -040081 vsDirtyConstF = VERTEX_UNIFORM_VECTORS + 1;
John Bauman89401822014-05-06 15:04:28 -040082 vsDirtyConstI = 16;
83 vsDirtyConstB = 16;
84
Alexis Hetu04c967a2015-07-08 15:56:17 -040085 psDirtyConstF = FRAGMENT_UNIFORM_VECTORS;
John Bauman89401822014-05-06 15:04:28 -040086 psDirtyConstI = 16;
87 psDirtyConstB = 16;
88
89 references = -1;
90
91 data = (DrawData*)allocate(sizeof(DrawData));
92 data->constants = &constants;
93 }
94
95 DrawCall::~DrawCall()
96 {
97 delete queries;
98
99 deallocate(data);
100 }
101
Nicolas Capens3aa46cb2015-06-03 16:33:02 -0400102 Renderer::Renderer(Context *context, Conventions conventions, bool exactColorRounding) : context(context), VertexProcessor(context), PixelProcessor(context), SetupProcessor(context), viewport()
John Bauman89401822014-05-06 15:04:28 -0400103 {
Nicolas Capens3aa46cb2015-06-03 16:33:02 -0400104 sw::halfIntegerCoordinates = conventions.halfIntegerCoordinates;
105 sw::symmetricNormalizedDepth = conventions.symmetricNormalizedDepth;
106 sw::booleanFaceRegister = conventions.booleanFaceRegister;
107 sw::fullPixelPositionRegister = conventions.fullPixelPositionRegister;
108 sw::leadingVertexFirst = conventions.leadingVertexFirst;
Nicolas Capens44ffb652015-08-04 16:11:24 -0400109 sw::secondaryColor = conventions.secondaryColor;
John Bauman19bac1e2014-05-06 15:23:49 -0400110 sw::exactColorRounding = exactColorRounding;
John Bauman89401822014-05-06 15:04:28 -0400111
John Bauman19bac1e2014-05-06 15:23:49 -0400112 setRenderTarget(0, 0);
John Bauman89401822014-05-06 15:04:28 -0400113 clipper = new Clipper();
114
John Bauman89401822014-05-06 15:04:28 -0400115 updateViewMatrix = true;
116 updateBaseMatrix = true;
117 updateProjectionMatrix = true;
118 updateClipPlanes = true;
119
120 #if PERF_HUD
121 resetTimers();
122 #endif
123
124 for(int i = 0; i < 16; i++)
125 {
126 vertexTask[i] = 0;
127
128 worker[i] = 0;
129 resume[i] = 0;
130 suspend[i] = 0;
131 }
132
133 threadsAwake = 0;
134 resumeApp = new Event();
135
136 currentDraw = 0;
137 nextDraw = 0;
138
139 qHead = 0;
140 qSize = 0;
141
142 for(int i = 0; i < 16; i++)
143 {
144 triangleBatch[i] = 0;
145 primitiveBatch[i] = 0;
146 }
147
148 for(int draw = 0; draw < DRAW_COUNT; draw++)
149 {
150 drawCall[draw] = new DrawCall();
151 drawList[draw] = drawCall[draw];
152 }
153
154 for(int unit = 0; unit < 16; unit++)
155 {
156 primitiveProgress[unit].init();
157 }
158
159 for(int cluster = 0; cluster < 16; cluster++)
160 {
161 pixelProgress[cluster].init();
162 }
163
164 clipFlags = 0;
165
166 swiftConfig = new SwiftConfig(disableServer);
167 updateConfiguration(true);
John Bauman19bac1e2014-05-06 15:23:49 -0400168
169 sync = new Resource(0);
John Bauman89401822014-05-06 15:04:28 -0400170 }
171
172 Renderer::~Renderer()
173 {
John Bauman19bac1e2014-05-06 15:23:49 -0400174 sync->destruct();
175
John Bauman89401822014-05-06 15:04:28 -0400176 delete clipper;
177 clipper = 0;
178
179 terminateThreads();
180 delete resumeApp;
181
182 for(int draw = 0; draw < DRAW_COUNT; draw++)
183 {
184 delete drawCall[draw];
185 }
186
John Bauman89401822014-05-06 15:04:28 -0400187 delete swiftConfig;
188 }
189
Alexis Hetu75b650f2015-11-19 17:40:15 -0500190 void Renderer::clear(void *pixel, Format format, Surface *dest, const SliceRect &dRect, unsigned int rgbaMask)
191 {
192 blitter.clear(pixel, format, dest, dRect, rgbaMask);
193 }
194
Alexis Hetuf7be67f2015-02-11 16:11:07 -0500195 void Renderer::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
John Bauman89401822014-05-06 15:04:28 -0400196 {
197 blitter.blit(source, sRect, dest, dRect, filter);
198 }
199
Alexis Hetuf68510d2015-02-24 14:33:49 -0500200 void Renderer::blit3D(Surface *source, Surface *dest)
201 {
202 blitter.blit3D(source, dest);
203 }
204
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400205 void Renderer::draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update)
John Bauman89401822014-05-06 15:04:28 -0400206 {
207 #ifndef NDEBUG
208 if(count < minPrimitives || count > maxPrimitives)
209 {
210 return;
211 }
212 #endif
213
214 context->drawType = drawType;
215
216 updateConfiguration();
217 updateClipper();
218
John Bauman66b8ab22014-05-06 15:57:45 -0400219 int ss = context->getSuperSampleCount();
220 int ms = context->getMultiSampleCount();
John Bauman89401822014-05-06 15:04:28 -0400221
222 for(int q = 0; q < ss; q++)
223 {
224 int oldMultiSampleMask = context->multiSampleMask;
John Bauman19bac1e2014-05-06 15:23:49 -0400225 context->multiSampleMask = (context->sampleMask >> (ms * q)) & ((unsigned)0xFFFFFFFF >> (32 - ms));
John Bauman89401822014-05-06 15:04:28 -0400226
227 if(!context->multiSampleMask)
228 {
229 continue;
230 }
231
John Bauman19bac1e2014-05-06 15:23:49 -0400232 sync->lock(sw::PRIVATE);
233
Nicolas Capens235781d2015-01-27 01:46:53 -0500234 Routine *vertexRoutine;
235 Routine *setupRoutine;
236 Routine *pixelRoutine;
237
John Bauman89401822014-05-06 15:04:28 -0400238 if(update || oldMultiSampleMask != context->multiSampleMask)
239 {
240 vertexState = VertexProcessor::update();
241 setupState = SetupProcessor::update();
242 pixelState = PixelProcessor::update();
243
244 vertexRoutine = VertexProcessor::routine(vertexState);
245 setupRoutine = SetupProcessor::routine(setupState);
246 pixelRoutine = PixelProcessor::routine(pixelState);
247 }
248
249 int batch = batchSize / ms;
250
Nicolas Capens235781d2015-01-27 01:46:53 -0500251 int (*setupPrimitives)(Renderer *renderer, int batch, int count);
252
John Bauman89401822014-05-06 15:04:28 -0400253 if(context->isDrawTriangle())
254 {
255 switch(context->fillMode)
256 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400257 case FILL_SOLID:
John Bauman89401822014-05-06 15:04:28 -0400258 setupPrimitives = setupSolidTriangles;
259 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400260 case FILL_WIREFRAME:
John Bauman89401822014-05-06 15:04:28 -0400261 setupPrimitives = setupWireframeTriangle;
262 batch = 1;
263 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400264 case FILL_VERTEX:
John Bauman89401822014-05-06 15:04:28 -0400265 setupPrimitives = setupVertexTriangle;
266 batch = 1;
267 break;
268 default: ASSERT(false);
269 }
270 }
271 else if(context->isDrawLine())
272 {
273 setupPrimitives = setupLines;
274 }
275 else // Point draw
276 {
277 setupPrimitives = setupPoints;
278 }
279
280 DrawCall *draw = 0;
281
282 do
283 {
284 for(int i = 0; i < DRAW_COUNT; i++)
285 {
286 if(drawCall[i]->references == -1)
287 {
288 draw = drawCall[i];
289 drawList[nextDraw % DRAW_COUNT] = draw;
290
291 break;
292 }
293 }
294
295 if(!draw)
296 {
297 resumeApp->wait();
298 }
299 }
300 while(!draw);
301
302 DrawData *data = draw->data;
303
304 if(queries.size() != 0)
305 {
306 for(std::list<Query*>::iterator query = queries.begin(); query != queries.end(); query++)
307 {
John Bauman66b8ab22014-05-06 15:57:45 -0400308 atomicIncrement(&(*query)->reference);
John Bauman89401822014-05-06 15:04:28 -0400309 }
310
311 draw->queries = new std::list<Query*>(queries);
312 }
313
314 draw->drawType = drawType;
315 draw->batchSize = batch;
316
317 vertexRoutine->bind();
318 setupRoutine->bind();
319 pixelRoutine->bind();
320
321 draw->vertexRoutine = vertexRoutine;
322 draw->setupRoutine = setupRoutine;
323 draw->pixelRoutine = pixelRoutine;
Nicolas Capenseb195b62015-04-28 17:18:42 -0700324 draw->vertexPointer = (VertexProcessor::RoutinePointer)vertexRoutine->getEntry();
John Bauman89401822014-05-06 15:04:28 -0400325 draw->setupPointer = (SetupProcessor::RoutinePointer)setupRoutine->getEntry();
326 draw->pixelPointer = (PixelProcessor::RoutinePointer)pixelRoutine->getEntry();
327 draw->setupPrimitives = setupPrimitives;
328 draw->setupState = setupState;
329
Nicolas Capens0f250902015-06-25 15:25:29 -0400330 for(int i = 0; i < VERTEX_ATTRIBUTES; i++)
John Bauman89401822014-05-06 15:04:28 -0400331 {
332 draw->vertexStream[i] = context->input[i].resource;
333 data->input[i] = context->input[i].buffer;
334 data->stride[i] = context->input[i].stride;
335
336 if(draw->vertexStream[i])
337 {
338 draw->vertexStream[i]->lock(PUBLIC, PRIVATE);
339 }
340 }
341
342 if(context->indexBuffer)
343 {
344 data->indices = (unsigned char*)context->indexBuffer->lock(PUBLIC, PRIVATE) + indexOffset;
345 }
346
347 draw->indexBuffer = context->indexBuffer;
348
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400349 for(int sampler = 0; sampler < TOTAL_IMAGE_UNITS; sampler++)
John Bauman89401822014-05-06 15:04:28 -0400350 {
351 draw->texture[sampler] = 0;
352 }
353
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400354 for(int sampler = 0; sampler < TEXTURE_IMAGE_UNITS; sampler++)
John Bauman89401822014-05-06 15:04:28 -0400355 {
356 if(pixelState.sampler[sampler].textureType != TEXTURE_NULL)
357 {
358 draw->texture[sampler] = context->texture[sampler];
359 draw->texture[sampler]->lock(PUBLIC, isReadWriteTexture(sampler) ? MANAGED : PRIVATE); // If the texure is both read and written, use the same read/write lock as render targets
360
361 data->mipmap[sampler] = context->sampler[sampler].getTextureData();
362 }
363 }
364
365 if(context->pixelShader)
366 {
367 if(draw->psDirtyConstF)
368 {
369 memcpy(&data->ps.cW, PixelProcessor::cW, sizeof(word4) * 4 * (draw->psDirtyConstF < 8 ? draw->psDirtyConstF : 8));
370 memcpy(&data->ps.c, PixelProcessor::c, sizeof(float4) * draw->psDirtyConstF);
371 draw->psDirtyConstF = 0;
372 }
373
374 if(draw->psDirtyConstI)
375 {
376 memcpy(&data->ps.i, PixelProcessor::i, sizeof(int4) * draw->psDirtyConstI);
377 draw->psDirtyConstI = 0;
378 }
379
380 if(draw->psDirtyConstB)
381 {
382 memcpy(&data->ps.b, PixelProcessor::b, sizeof(bool) * draw->psDirtyConstB);
383 draw->psDirtyConstB = 0;
384 }
385 }
386
387 if(context->pixelShaderVersion() <= 0x0104)
388 {
389 for(int stage = 0; stage < 8; stage++)
390 {
391 if(pixelState.textureStage[stage].stageOperation != TextureStage::STAGE_DISABLE || context->pixelShader)
392 {
393 data->textureStage[stage] = context->textureStage[stage].uniforms;
394 }
395 else break;
396 }
397 }
398
399 if(context->vertexShader)
400 {
401 if(context->vertexShader->getVersion() >= 0x0300)
402 {
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400403 for(int sampler = 0; sampler < VERTEX_TEXTURE_IMAGE_UNITS; sampler++)
John Bauman89401822014-05-06 15:04:28 -0400404 {
405 if(vertexState.samplerState[sampler].textureType != TEXTURE_NULL)
406 {
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400407 draw->texture[TEXTURE_IMAGE_UNITS + sampler] = context->texture[TEXTURE_IMAGE_UNITS + sampler];
408 draw->texture[TEXTURE_IMAGE_UNITS + sampler]->lock(PUBLIC, PRIVATE);
John Bauman89401822014-05-06 15:04:28 -0400409
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400410 data->mipmap[TEXTURE_IMAGE_UNITS + sampler] = context->sampler[TEXTURE_IMAGE_UNITS + sampler].getTextureData();
John Bauman89401822014-05-06 15:04:28 -0400411 }
412 }
413 }
414
415 if(draw->vsDirtyConstF)
416 {
417 memcpy(&data->vs.c, VertexProcessor::c, sizeof(float4) * draw->vsDirtyConstF);
418 draw->vsDirtyConstF = 0;
419 }
420
421 if(draw->vsDirtyConstI)
422 {
423 memcpy(&data->vs.i, VertexProcessor::i, sizeof(int4) * draw->vsDirtyConstI);
424 draw->vsDirtyConstI = 0;
425 }
426
427 if(draw->vsDirtyConstB)
428 {
429 memcpy(&data->vs.b, VertexProcessor::b, sizeof(bool) * draw->vsDirtyConstB);
430 draw->vsDirtyConstB = 0;
431 }
Alexis Hetudd8df682015-06-05 17:08:39 -0400432
433 if(context->vertexShader->instanceIdDeclared)
434 {
435 data->instanceID = context->instanceID;
436 }
John Bauman89401822014-05-06 15:04:28 -0400437 }
438 else
439 {
440 data->ff = ff;
441
Alexis Hetu04c967a2015-07-08 15:56:17 -0400442 draw->vsDirtyConstF = VERTEX_UNIFORM_VECTORS + 1;
John Bauman89401822014-05-06 15:04:28 -0400443 draw->vsDirtyConstI = 16;
444 draw->vsDirtyConstB = 16;
445 }
446
447 if(pixelState.stencilActive)
448 {
449 data->stencil[0] = stencil;
450 data->stencil[1] = stencilCCW;
451 }
452
453 if(pixelState.fogActive)
454 {
455 data->fog = fog;
456 }
457
458 if(setupState.isDrawPoint)
459 {
460 data->point = point;
461 }
462
Nicolas Capens235781d2015-01-27 01:46:53 -0500463 data->lineWidth = context->lineWidth;
464
John Bauman89401822014-05-06 15:04:28 -0400465 data->factor = factor;
466
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400467 if(pixelState.transparencyAntialiasing == TRANSPARENCY_ALPHA_TO_COVERAGE)
John Bauman89401822014-05-06 15:04:28 -0400468 {
Alexis Hetua818c452015-06-11 13:06:58 -0400469 float ref = context->alphaReference * (1.0f / 255.0f);
John Bauman89401822014-05-06 15:04:28 -0400470 float margin = sw::min(ref, 1.0f - ref);
471
472 if(ms == 4)
473 {
474 data->a2c0 = replicate(ref - margin * 0.6f);
475 data->a2c1 = replicate(ref - margin * 0.2f);
476 data->a2c2 = replicate(ref + margin * 0.2f);
477 data->a2c3 = replicate(ref + margin * 0.6f);
478 }
479 else if(ms == 2)
480 {
481 data->a2c0 = replicate(ref - margin * 0.3f);
482 data->a2c1 = replicate(ref + margin * 0.3f);
483 }
484 else ASSERT(false);
485 }
486
487 if(pixelState.occlusionEnabled)
488 {
489 for(int cluster = 0; cluster < clusterCount; cluster++)
490 {
491 data->occlusion[cluster] = 0;
492 }
493 }
494
495 #if PERF_PROFILE
496 for(int cluster = 0; cluster < clusterCount; cluster++)
497 {
498 for(int i = 0; i < PERF_TIMERS; i++)
499 {
500 data->cycles[i][cluster] = 0;
501 }
502 }
503 #endif
504
505 // Viewport
506 {
John Bauman19bac1e2014-05-06 15:23:49 -0400507 float W = 0.5f * viewport.width;
508 float H = 0.5f * viewport.height;
509 float X0 = viewport.x0 + W;
510 float Y0 = viewport.y0 + H;
511 float N = viewport.minZ;
512 float F = viewport.maxZ;
John Bauman89401822014-05-06 15:04:28 -0400513 float Z = F - N;
514
515 if(context->isDrawTriangle(false))
516 {
517 N += depthBias;
518 }
519
520 if(complementaryDepthBuffer)
521 {
522 Z = -Z;
523 N = 1 - N;
524 }
525
526 static const float X[5][16] = // Fragment offsets
527 {
528 {+0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 1 sample
529 {-0.2500f, +0.2500f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 2 samples
530 {-0.3000f, +0.1000f, +0.3000f, -0.1000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 4 samples
531 {+0.1875f, -0.3125f, +0.3125f, -0.4375f, -0.0625f, +0.4375f, +0.0625f, -0.1875f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 8 samples
532 {+0.2553f, -0.1155f, +0.1661f, -0.1828f, +0.2293f, -0.4132f, -0.1773f, -0.0577f, +0.3891f, -0.4656f, +0.4103f, +0.4248f, -0.2109f, +0.3966f, -0.2664f, -0.3872f} // 16 samples
533 };
534
535 static const float Y[5][16] = // Fragment offsets
536 {
537 {+0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 1 sample
538 {-0.2500f, +0.2500f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 2 samples
539 {-0.1000f, -0.3000f, +0.1000f, +0.3000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 4 samples
540 {-0.4375f, -0.3125f, -0.1875f, -0.0625f, +0.0625f, +0.1875f, +0.3125f, +0.4375f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f, +0.0000f}, // 8 samples
541 {-0.4503f, +0.1883f, +0.3684f, -0.4668f, -0.0690f, -0.1315f, +0.4999f, +0.0728f, +0.1070f, -0.3086f, +0.3725f, -0.1547f, -0.1102f, -0.3588f, +0.1789f, +0.0269f} // 16 samples
542 };
543
544 int s = sw::log2(ss);
545
John Bauman19bac1e2014-05-06 15:23:49 -0400546 data->Wx16 = replicate(W * 16);
547 data->Hx16 = replicate(H * 16);
Nicolas Capens5491cb42015-07-02 15:33:29 -0400548 data->X0x16 = replicate(X0 * 16 - 8);
549 data->Y0x16 = replicate(Y0 * 16 - 8);
John Bauman89401822014-05-06 15:04:28 -0400550 data->XXXX = replicate(X[s][q] / W);
551 data->YYYY = replicate(Y[s][q] / H);
John Bauman19bac1e2014-05-06 15:23:49 -0400552 data->halfPixelX = replicate(0.5f / W);
553 data->halfPixelY = replicate(0.5f / H);
554 data->viewportHeight = abs(viewport.height);
John Bauman89401822014-05-06 15:04:28 -0400555 data->slopeDepthBias = slopeDepthBias;
556 data->depthRange = Z;
557 data->depthNear = N;
558 draw->clipFlags = clipFlags;
559
560 if(clipFlags)
561 {
562 if(clipFlags & Clipper::CLIP_PLANE0) data->clipPlane[0] = clipPlane[0];
563 if(clipFlags & Clipper::CLIP_PLANE1) data->clipPlane[1] = clipPlane[1];
564 if(clipFlags & Clipper::CLIP_PLANE2) data->clipPlane[2] = clipPlane[2];
565 if(clipFlags & Clipper::CLIP_PLANE3) data->clipPlane[3] = clipPlane[3];
566 if(clipFlags & Clipper::CLIP_PLANE4) data->clipPlane[4] = clipPlane[4];
567 if(clipFlags & Clipper::CLIP_PLANE5) data->clipPlane[5] = clipPlane[5];
568 }
569 }
570
571 // Target
572 {
Alexis Hetu1edcd8b2015-11-05 11:12:41 -0500573 for(int index = 0; index < RENDERTARGETS; index++)
John Bauman89401822014-05-06 15:04:28 -0400574 {
575 draw->renderTarget[index] = context->renderTarget[index];
576
577 if(draw->renderTarget[index])
578 {
579 data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->lockInternal(0, 0, q * ms, LOCK_READWRITE, MANAGED);
580 data->colorPitchB[index] = context->renderTarget[index]->getInternalPitchB();
581 data->colorSliceB[index] = context->renderTarget[index]->getInternalSliceB();
582 }
583 }
584
585 draw->depthStencil = context->depthStencil;
586
587 if(draw->depthStencil)
588 {
589 data->depthBuffer = (float*)context->depthStencil->lockInternal(0, 0, q * ms, LOCK_READWRITE, MANAGED);
590 data->depthPitchB = context->depthStencil->getInternalPitchB();
591 data->depthSliceB = context->depthStencil->getInternalSliceB();
592
593 data->stencilBuffer = (unsigned char*)context->depthStencil->lockStencil(q * ms, MANAGED);
594 data->stencilPitchB = context->depthStencil->getStencilPitchB();
595 data->stencilSliceB = context->depthStencil->getStencilSliceB();
596 }
597 }
598
John Bauman19bac1e2014-05-06 15:23:49 -0400599 // Scissor
600 {
601 data->scissorX0 = scissor.x0;
602 data->scissorX1 = scissor.x1;
603 data->scissorY0 = scissor.y0;
604 data->scissorY1 = scissor.y1;
605 }
606
John Bauman89401822014-05-06 15:04:28 -0400607 draw->primitive = 0;
608 draw->count = count;
609
610 draw->references = (count + batch - 1) / batch;
611
Nicolas Capensebe67642015-03-20 13:34:51 -0400612 schedulerMutex.lock();
John Bauman89401822014-05-06 15:04:28 -0400613 nextDraw++;
Nicolas Capensebe67642015-03-20 13:34:51 -0400614 schedulerMutex.unlock();
John Bauman89401822014-05-06 15:04:28 -0400615
Nicolas Capens20248dd2015-08-10 14:07:45 -0400616 if(threadCount > 1)
John Bauman89401822014-05-06 15:04:28 -0400617 {
Nicolas Capens20248dd2015-08-10 14:07:45 -0400618 if(!threadsAwake)
619 {
620 suspend[0]->wait();
John Bauman89401822014-05-06 15:04:28 -0400621
Nicolas Capens20248dd2015-08-10 14:07:45 -0400622 threadsAwake = 1;
623 task[0].type = Task::RESUME;
624
625 resume[0]->signal();
626 }
627 }
628 else // Use main thread for draw execution
629 {
John Bauman89401822014-05-06 15:04:28 -0400630 threadsAwake = 1;
631 task[0].type = Task::RESUME;
632
Nicolas Capens20248dd2015-08-10 14:07:45 -0400633 taskLoop(0);
John Bauman89401822014-05-06 15:04:28 -0400634 }
635 }
636 }
637
638 void Renderer::threadFunction(void *parameters)
639 {
640 Renderer *renderer = static_cast<Parameters*>(parameters)->renderer;
641 int threadIndex = static_cast<Parameters*>(parameters)->threadIndex;
642
643 if(logPrecision < IEEE)
644 {
John Bauman66b8ab22014-05-06 15:57:45 -0400645 CPUID::setFlushToZero(true);
646 CPUID::setDenormalsAreZero(true);
John Bauman89401822014-05-06 15:04:28 -0400647 }
648
649 renderer->threadLoop(threadIndex);
650 }
651
652 void Renderer::threadLoop(int threadIndex)
653 {
654 while(!exitThreads)
655 {
656 taskLoop(threadIndex);
657
658 suspend[threadIndex]->signal();
659 resume[threadIndex]->wait();
660 }
661 }
662
663 void Renderer::taskLoop(int threadIndex)
664 {
665 while(task[threadIndex].type != Task::SUSPEND)
666 {
667 scheduleTask(threadIndex);
668 executeTask(threadIndex);
669 }
670 }
671
672 void Renderer::findAvailableTasks()
673 {
674 // Find pixel tasks
675 for(int cluster = 0; cluster < clusterCount; cluster++)
676 {
677 if(!pixelProgress[cluster].executing)
678 {
679 for(int unit = 0; unit < unitCount; unit++)
680 {
681 if(primitiveProgress[unit].references > 0) // Contains processed primitives
682 {
683 if(pixelProgress[cluster].drawCall == primitiveProgress[unit].drawCall)
684 {
685 if(pixelProgress[cluster].processedPrimitives == primitiveProgress[unit].firstPrimitive) // Previous primitives have been rendered
686 {
687 Task &task = taskQueue[qHead];
688 task.type = Task::PIXELS;
689 task.primitiveUnit = unit;
690 task.pixelCluster = cluster;
691
692 pixelProgress[cluster].executing = true;
693
694 // Commit to the task queue
695 qHead = (qHead + 1) % 32;
696 qSize++;
697
698 break;
699 }
700 }
701 }
702 }
703 }
704 }
705
706 // Find primitive tasks
707 if(currentDraw == nextDraw)
708 {
709 return; // No more primitives to process
710 }
711
712 for(int unit = 0; unit < unitCount; unit++)
713 {
714 DrawCall *draw = drawList[currentDraw % DRAW_COUNT];
715
716 if(draw->primitive >= draw->count)
717 {
718 currentDraw++;
719
720 if(currentDraw == nextDraw)
721 {
722 return; // No more primitives to process
723 }
724
725 draw = drawList[currentDraw % DRAW_COUNT];
726 }
727
728 if(!primitiveProgress[unit].references) // Task not already being executed and not still in use by a pixel unit
729 {
730 int primitive = draw->primitive;
731 int count = draw->count;
732 int batch = draw->batchSize;
733
734 primitiveProgress[unit].drawCall = currentDraw;
735 primitiveProgress[unit].firstPrimitive = primitive;
736 primitiveProgress[unit].primitiveCount = count - primitive >= batch ? batch : count - primitive;
737
738 draw->primitive += batch;
739
740 Task &task = taskQueue[qHead];
741 task.type = Task::PRIMITIVES;
742 task.primitiveUnit = unit;
743
744 primitiveProgress[unit].references = -1;
745
746 // Commit to the task queue
747 qHead = (qHead + 1) % 32;
748 qSize++;
749 }
750 }
751 }
752
753 void Renderer::scheduleTask(int threadIndex)
754 {
Nicolas Capensebe67642015-03-20 13:34:51 -0400755 schedulerMutex.lock();
John Bauman89401822014-05-06 15:04:28 -0400756
757 if((int)qSize < threadCount - threadsAwake + 1)
758 {
759 findAvailableTasks();
760 }
761
762 if(qSize != 0)
763 {
764 task[threadIndex] = taskQueue[(qHead - qSize) % 32];
765 qSize--;
766
767 if(threadsAwake != threadCount)
768 {
769 int wakeup = qSize - threadsAwake + 1;
770
771 for(int i = 0; i < threadCount && wakeup > 0; i++)
772 {
773 if(task[i].type == Task::SUSPEND)
774 {
775 suspend[i]->wait();
776 task[i].type = Task::RESUME;
777 resume[i]->signal();
778
779 threadsAwake++;
780 wakeup--;
781 }
782 }
783 }
784 }
785 else
786 {
787 task[threadIndex].type = Task::SUSPEND;
788
789 threadsAwake--;
790 }
791
Nicolas Capensebe67642015-03-20 13:34:51 -0400792 schedulerMutex.unlock();
John Bauman89401822014-05-06 15:04:28 -0400793 }
794
795 void Renderer::executeTask(int threadIndex)
796 {
797 #if PERF_HUD
798 int64_t startTick = Timer::ticks();
799 #endif
800
801 switch(task[threadIndex].type)
802 {
803 case Task::PRIMITIVES:
804 {
805 int unit = task[threadIndex].primitiveUnit;
806
807 int input = primitiveProgress[unit].firstPrimitive;
808 int count = primitiveProgress[unit].primitiveCount;
809 DrawCall *draw = drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
810 int (*setupPrimitives)(Renderer *renderer, int batch, int count) = draw->setupPrimitives;
811
812 processPrimitiveVertices(unit, input, count, draw->count, threadIndex);
813
814 #if PERF_HUD
815 int64_t time = Timer::ticks();
816 vertexTime[threadIndex] += time - startTick;
817 startTick = time;
818 #endif
819
820 int visible = setupPrimitives(this, unit, count);
821
822 primitiveProgress[unit].visible = visible;
823 primitiveProgress[unit].references = clusterCount;
824
825 #if PERF_HUD
826 setupTime[threadIndex] += Timer::ticks() - startTick;
827 #endif
828 }
829 break;
830 case Task::PIXELS:
831 {
832 int unit = task[threadIndex].primitiveUnit;
833 int visible = primitiveProgress[unit].visible;
834
835 if(visible > 0)
836 {
837 int cluster = task[threadIndex].pixelCluster;
838 Primitive *primitive = primitiveBatch[unit];
839 DrawCall *draw = drawList[pixelProgress[cluster].drawCall % DRAW_COUNT];
840 DrawData *data = draw->data;
841 PixelProcessor::RoutinePointer pixelRoutine = draw->pixelPointer;
842
843 pixelRoutine(primitive, visible, cluster, data);
844 }
845
846 finishRendering(task[threadIndex]);
847
848 #if PERF_HUD
849 pixelTime[threadIndex] += Timer::ticks() - startTick;
850 #endif
851 }
852 break;
853 case Task::RESUME:
854 break;
855 case Task::SUSPEND:
856 break;
857 default:
858 ASSERT(false);
859 }
860 }
861
John Bauman19bac1e2014-05-06 15:23:49 -0400862 void Renderer::synchronize()
863 {
864 sync->lock(sw::PUBLIC);
865 sync->unlock();
866 }
867
John Bauman89401822014-05-06 15:04:28 -0400868 void Renderer::finishRendering(Task &pixelTask)
869 {
870 int unit = pixelTask.primitiveUnit;
871 int cluster = pixelTask.pixelCluster;
872
873 DrawCall &draw = *drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
874 DrawData &data = *draw.data;
875 int primitive = primitiveProgress[unit].firstPrimitive;
876 int count = primitiveProgress[unit].primitiveCount;
877
878 pixelProgress[cluster].processedPrimitives = primitive + count;
879
880 if(pixelProgress[cluster].processedPrimitives >= draw.count)
881 {
882 pixelProgress[cluster].drawCall++;
883 pixelProgress[cluster].processedPrimitives = 0;
884 }
885
John Bauman66b8ab22014-05-06 15:57:45 -0400886 int ref = atomicDecrement(&primitiveProgress[unit].references);
John Bauman89401822014-05-06 15:04:28 -0400887
888 if(ref == 0)
889 {
John Bauman66b8ab22014-05-06 15:57:45 -0400890 ref = atomicDecrement(&draw.references);
John Bauman89401822014-05-06 15:04:28 -0400891
892 if(ref == 0)
893 {
894 #if PERF_PROFILE
895 for(int cluster = 0; cluster < clusterCount; cluster++)
896 {
897 for(int i = 0; i < PERF_TIMERS; i++)
898 {
899 profiler.cycles[i] += data.cycles[i][cluster];
900 }
901 }
902 #endif
903
904 if(draw.queries)
905 {
906 for(std::list<Query*>::iterator q = draw.queries->begin(); q != draw.queries->end(); q++)
907 {
908 Query *query = *q;
909
910 for(int cluster = 0; cluster < clusterCount; cluster++)
911 {
John Bauman66b8ab22014-05-06 15:57:45 -0400912 atomicAdd((volatile int*)&query->data, data.occlusion[cluster]);
John Bauman89401822014-05-06 15:04:28 -0400913 }
914
John Bauman66b8ab22014-05-06 15:57:45 -0400915 atomicDecrement(&query->reference);
John Bauman89401822014-05-06 15:04:28 -0400916 }
917
918 delete draw.queries;
919 draw.queries = 0;
920 }
921
Alexis Hetu1edcd8b2015-11-05 11:12:41 -0500922 for(int i = 0; i < RENDERTARGETS; i++)
John Bauman89401822014-05-06 15:04:28 -0400923 {
924 if(draw.renderTarget[i])
925 {
926 draw.renderTarget[i]->unlockInternal();
927 }
928 }
929
930 if(draw.depthStencil)
931 {
932 draw.depthStencil->unlockInternal();
933 draw.depthStencil->unlockStencil();
934 }
935
Alexis Hetu0b65c5e2015-03-31 11:48:57 -0400936 for(int i = 0; i < TOTAL_IMAGE_UNITS; i++)
John Bauman89401822014-05-06 15:04:28 -0400937 {
938 if(draw.texture[i])
939 {
940 draw.texture[i]->unlock();
941 }
942 }
943
Nicolas Capens0f250902015-06-25 15:25:29 -0400944 for(int i = 0; i < VERTEX_ATTRIBUTES; i++)
John Bauman89401822014-05-06 15:04:28 -0400945 {
946 if(draw.vertexStream[i])
947 {
948 draw.vertexStream[i]->unlock();
949 }
950 }
951
952 if(draw.indexBuffer)
953 {
954 draw.indexBuffer->unlock();
955 }
956
957 draw.vertexRoutine->unbind();
958 draw.setupRoutine->unbind();
959 draw.pixelRoutine->unbind();
960
John Bauman19bac1e2014-05-06 15:23:49 -0400961 sync->unlock();
962
John Bauman89401822014-05-06 15:04:28 -0400963 draw.references = -1;
964 resumeApp->signal();
965 }
966 }
967
968 pixelProgress[cluster].executing = false;
969 }
970
Nicolas Capensc50d35d2015-01-27 01:52:41 -0500971 void Renderer::processPrimitiveVertices(int unit, unsigned int start, unsigned int triangleCount, unsigned int loop, int thread)
John Bauman89401822014-05-06 15:04:28 -0400972 {
973 Triangle *triangle = triangleBatch[unit];
974 DrawCall *draw = drawList[primitiveProgress[unit].drawCall % DRAW_COUNT];
975 DrawData *data = draw->data;
976 VertexTask *task = vertexTask[thread];
977
978 const void *indices = data->indices;
979 VertexProcessor::RoutinePointer vertexRoutine = draw->vertexPointer;
980
981 if(task->vertexCache.drawCall != primitiveProgress[unit].drawCall)
982 {
983 task->vertexCache.clear();
984 task->vertexCache.drawCall = primitiveProgress[unit].drawCall;
985 }
986
987 unsigned int batch[128][3]; // FIXME: Adjust to dynamic batch size
988
989 switch(draw->drawType)
990 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -0400991 case DRAW_POINTLIST:
John Bauman89401822014-05-06 15:04:28 -0400992 {
993 unsigned int index = start;
994
Nicolas Capensc50d35d2015-01-27 01:52:41 -0500995 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -0400996 {
997 batch[i][0] = index;
998 batch[i][1] = index;
999 batch[i][2] = index;
1000
1001 index += 1;
1002 }
1003 }
1004 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001005 case DRAW_LINELIST:
John Bauman89401822014-05-06 15:04:28 -04001006 {
1007 unsigned int index = 2 * start;
1008
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001009 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001010 {
1011 batch[i][0] = index + 0;
1012 batch[i][1] = index + 1;
1013 batch[i][2] = index + 1;
1014
1015 index += 2;
1016 }
1017 }
1018 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001019 case DRAW_LINESTRIP:
John Bauman89401822014-05-06 15:04:28 -04001020 {
1021 unsigned int index = start;
1022
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001023 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001024 {
1025 batch[i][0] = index + 0;
1026 batch[i][1] = index + 1;
1027 batch[i][2] = index + 1;
1028
1029 index += 1;
1030 }
1031 }
1032 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001033 case DRAW_LINELOOP:
John Bauman89401822014-05-06 15:04:28 -04001034 {
1035 unsigned int index = start;
1036
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001037 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001038 {
1039 batch[i][0] = (index + 0) % loop;
1040 batch[i][1] = (index + 1) % loop;
1041 batch[i][2] = (index + 1) % loop;
1042
1043 index += 1;
1044 }
1045 }
1046 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001047 case DRAW_TRIANGLELIST:
John Bauman89401822014-05-06 15:04:28 -04001048 {
1049 unsigned int index = 3 * start;
1050
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001051 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001052 {
1053 batch[i][0] = index + 0;
1054 batch[i][1] = index + 1;
1055 batch[i][2] = index + 2;
1056
1057 index += 3;
1058 }
1059 }
1060 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001061 case DRAW_TRIANGLESTRIP:
John Bauman89401822014-05-06 15:04:28 -04001062 {
1063 unsigned int index = start;
1064
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001065 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001066 {
1067 batch[i][0] = index + 0;
1068 batch[i][1] = index + (index & 1) + 1;
1069 batch[i][2] = index + (~index & 1) + 1;
1070
1071 index += 1;
1072 }
1073 }
1074 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001075 case DRAW_TRIANGLEFAN:
John Bauman89401822014-05-06 15:04:28 -04001076 {
1077 unsigned int index = start;
1078
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001079 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001080 {
1081 batch[i][0] = index + 1;
1082 batch[i][1] = index + 2;
1083 batch[i][2] = 0;
1084
1085 index += 1;
1086 }
1087 }
1088 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001089 case DRAW_INDEXEDPOINTLIST8:
John Bauman89401822014-05-06 15:04:28 -04001090 {
1091 const unsigned char *index = (const unsigned char*)indices + start;
1092
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001093 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001094 {
1095 batch[i][0] = *index;
1096 batch[i][1] = *index;
1097 batch[i][2] = *index;
1098
1099 index += 1;
1100 }
1101 }
1102 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001103 case DRAW_INDEXEDPOINTLIST16:
John Bauman89401822014-05-06 15:04:28 -04001104 {
1105 const unsigned short *index = (const unsigned short*)indices + start;
1106
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001107 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001108 {
1109 batch[i][0] = *index;
1110 batch[i][1] = *index;
1111 batch[i][2] = *index;
1112
1113 index += 1;
1114 }
1115 }
1116 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001117 case DRAW_INDEXEDPOINTLIST32:
John Bauman89401822014-05-06 15:04:28 -04001118 {
1119 const unsigned int *index = (const unsigned int*)indices + start;
1120
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001121 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001122 {
1123 batch[i][0] = *index;
1124 batch[i][1] = *index;
1125 batch[i][2] = *index;
1126
1127 index += 1;
1128 }
1129 }
1130 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001131 case DRAW_INDEXEDLINELIST8:
John Bauman89401822014-05-06 15:04:28 -04001132 {
1133 const unsigned char *index = (const unsigned char*)indices + 2 * start;
1134
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001135 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001136 {
1137 batch[i][0] = index[0];
1138 batch[i][1] = index[1];
1139 batch[i][2] = index[1];
1140
1141 index += 2;
1142 }
1143 }
1144 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001145 case DRAW_INDEXEDLINELIST16:
John Bauman89401822014-05-06 15:04:28 -04001146 {
1147 const unsigned short *index = (const unsigned short*)indices + 2 * start;
1148
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001149 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001150 {
1151 batch[i][0] = index[0];
1152 batch[i][1] = index[1];
1153 batch[i][2] = index[1];
1154
1155 index += 2;
1156 }
1157 }
1158 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001159 case DRAW_INDEXEDLINELIST32:
John Bauman89401822014-05-06 15:04:28 -04001160 {
1161 const unsigned int *index = (const unsigned int*)indices + 2 * start;
1162
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001163 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001164 {
1165 batch[i][0] = index[0];
1166 batch[i][1] = index[1];
1167 batch[i][2] = index[1];
1168
1169 index += 2;
1170 }
1171 }
1172 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001173 case DRAW_INDEXEDLINESTRIP8:
John Bauman89401822014-05-06 15:04:28 -04001174 {
1175 const unsigned char *index = (const unsigned char*)indices + start;
1176
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001177 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001178 {
1179 batch[i][0] = index[0];
1180 batch[i][1] = index[1];
1181 batch[i][2] = index[1];
1182
1183 index += 1;
1184 }
1185 }
1186 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001187 case DRAW_INDEXEDLINESTRIP16:
John Bauman89401822014-05-06 15:04:28 -04001188 {
1189 const unsigned short *index = (const unsigned short*)indices + start;
1190
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001191 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001192 {
1193 batch[i][0] = index[0];
1194 batch[i][1] = index[1];
1195 batch[i][2] = index[1];
1196
1197 index += 1;
1198 }
1199 }
1200 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001201 case DRAW_INDEXEDLINESTRIP32:
John Bauman89401822014-05-06 15:04:28 -04001202 {
1203 const unsigned int *index = (const unsigned int*)indices + start;
1204
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001205 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001206 {
1207 batch[i][0] = index[0];
1208 batch[i][1] = index[1];
1209 batch[i][2] = index[1];
1210
1211 index += 1;
1212 }
1213 }
1214 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001215 case DRAW_INDEXEDLINELOOP8:
John Bauman89401822014-05-06 15:04:28 -04001216 {
John Bauman66b8ab22014-05-06 15:57:45 -04001217 const unsigned char *index = (const unsigned char*)indices;
John Bauman89401822014-05-06 15:04:28 -04001218
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001219 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001220 {
John Bauman66b8ab22014-05-06 15:57:45 -04001221 batch[i][0] = index[(start + i + 0) % loop];
1222 batch[i][1] = index[(start + i + 1) % loop];
1223 batch[i][2] = index[(start + i + 1) % loop];
John Bauman89401822014-05-06 15:04:28 -04001224 }
1225 }
1226 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001227 case DRAW_INDEXEDLINELOOP16:
John Bauman89401822014-05-06 15:04:28 -04001228 {
John Bauman66b8ab22014-05-06 15:57:45 -04001229 const unsigned short *index = (const unsigned short*)indices;
John Bauman89401822014-05-06 15:04:28 -04001230
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001231 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001232 {
John Bauman66b8ab22014-05-06 15:57:45 -04001233 batch[i][0] = index[(start + i + 0) % loop];
1234 batch[i][1] = index[(start + i + 1) % loop];
1235 batch[i][2] = index[(start + i + 1) % loop];
John Bauman89401822014-05-06 15:04:28 -04001236 }
1237 }
1238 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001239 case DRAW_INDEXEDLINELOOP32:
John Bauman89401822014-05-06 15:04:28 -04001240 {
John Bauman66b8ab22014-05-06 15:57:45 -04001241 const unsigned int *index = (const unsigned int*)indices;
John Bauman89401822014-05-06 15:04:28 -04001242
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001243 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001244 {
John Bauman66b8ab22014-05-06 15:57:45 -04001245 batch[i][0] = index[(start + i + 0) % loop];
1246 batch[i][1] = index[(start + i + 1) % loop];
1247 batch[i][2] = index[(start + i + 1) % loop];
John Bauman89401822014-05-06 15:04:28 -04001248 }
1249 }
1250 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001251 case DRAW_INDEXEDTRIANGLELIST8:
John Bauman89401822014-05-06 15:04:28 -04001252 {
1253 const unsigned char *index = (const unsigned char*)indices + 3 * start;
1254
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001255 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001256 {
1257 batch[i][0] = index[0];
1258 batch[i][1] = index[1];
1259 batch[i][2] = index[2];
1260
1261 index += 3;
1262 }
1263 }
1264 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001265 case DRAW_INDEXEDTRIANGLELIST16:
John Bauman89401822014-05-06 15:04:28 -04001266 {
1267 const unsigned short *index = (const unsigned short*)indices + 3 * start;
1268
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001269 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001270 {
1271 batch[i][0] = index[0];
1272 batch[i][1] = index[1];
1273 batch[i][2] = index[2];
1274
1275 index += 3;
1276 }
1277 }
1278 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001279 case DRAW_INDEXEDTRIANGLELIST32:
John Bauman89401822014-05-06 15:04:28 -04001280 {
1281 const unsigned int *index = (const unsigned int*)indices + 3 * start;
1282
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001283 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001284 {
1285 batch[i][0] = index[0];
1286 batch[i][1] = index[1];
1287 batch[i][2] = index[2];
1288
1289 index += 3;
1290 }
1291 }
1292 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001293 case DRAW_INDEXEDTRIANGLESTRIP8:
John Bauman89401822014-05-06 15:04:28 -04001294 {
1295 const unsigned char *index = (const unsigned char*)indices + start;
1296
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001297 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001298 {
1299 batch[i][0] = index[0];
1300 batch[i][1] = index[((start + i) & 1) + 1];
1301 batch[i][2] = index[(~(start + i) & 1) + 1];
1302
1303 index += 1;
1304 }
1305 }
1306 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001307 case DRAW_INDEXEDTRIANGLESTRIP16:
John Bauman89401822014-05-06 15:04:28 -04001308 {
1309 const unsigned short *index = (const unsigned short*)indices + start;
1310
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001311 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001312 {
1313 batch[i][0] = index[0];
1314 batch[i][1] = index[((start + i) & 1) + 1];
1315 batch[i][2] = index[(~(start + i) & 1) + 1];
1316
1317 index += 1;
1318 }
1319 }
1320 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001321 case DRAW_INDEXEDTRIANGLESTRIP32:
John Bauman89401822014-05-06 15:04:28 -04001322 {
1323 const unsigned int *index = (const unsigned int*)indices + start;
1324
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001325 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001326 {
1327 batch[i][0] = index[0];
1328 batch[i][1] = index[((start + i) & 1) + 1];
1329 batch[i][2] = index[(~(start + i) & 1) + 1];
1330
1331 index += 1;
1332 }
1333 }
1334 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001335 case DRAW_INDEXEDTRIANGLEFAN8:
John Bauman89401822014-05-06 15:04:28 -04001336 {
1337 const unsigned char *index = (const unsigned char*)indices;
1338
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001339 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001340 {
1341 batch[i][0] = index[start + i + 1];
1342 batch[i][1] = index[start + i + 2];
1343 batch[i][2] = index[0];
1344 }
1345 }
1346 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001347 case DRAW_INDEXEDTRIANGLEFAN16:
John Bauman89401822014-05-06 15:04:28 -04001348 {
1349 const unsigned short *index = (const unsigned short*)indices;
1350
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001351 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001352 {
1353 batch[i][0] = index[start + i + 1];
1354 batch[i][1] = index[start + i + 2];
1355 batch[i][2] = index[0];
1356 }
1357 }
1358 break;
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001359 case DRAW_INDEXEDTRIANGLEFAN32:
John Bauman89401822014-05-06 15:04:28 -04001360 {
1361 const unsigned int *index = (const unsigned int*)indices;
1362
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001363 for(unsigned int i = 0; i < triangleCount; i++)
John Bauman89401822014-05-06 15:04:28 -04001364 {
1365 batch[i][0] = index[start + i + 1];
1366 batch[i][1] = index[start + i + 2];
1367 batch[i][2] = index[0];
1368 }
1369 }
1370 break;
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001371 case DRAW_QUADLIST:
1372 {
1373 unsigned int index = 4 * start / 2;
1374
1375 for(unsigned int i = 0; i < triangleCount; i += 2)
1376 {
1377 batch[i+0][0] = index + 0;
1378 batch[i+0][1] = index + 1;
1379 batch[i+0][2] = index + 2;
1380
1381 batch[i+1][0] = index + 0;
1382 batch[i+1][1] = index + 2;
1383 batch[i+1][2] = index + 3;
1384
1385 index += 4;
1386 }
1387 }
1388 break;
John Bauman89401822014-05-06 15:04:28 -04001389 default:
1390 ASSERT(false);
1391 }
1392
Nicolas Capensc50d35d2015-01-27 01:52:41 -05001393 task->vertexCount = triangleCount * 3;
John Bauman89401822014-05-06 15:04:28 -04001394 vertexRoutine(&triangle->v0, (unsigned int*)&batch, task, data);
1395 }
1396
1397 int Renderer::setupSolidTriangles(Renderer *renderer, int unit, int count)
1398 {
1399 Triangle *triangle = renderer->triangleBatch[unit];
1400 Primitive *primitive = renderer->primitiveBatch[unit];
1401
1402 DrawCall &draw = *renderer->drawList[renderer->primitiveProgress[unit].drawCall % DRAW_COUNT];
1403 SetupProcessor::State &state = draw.setupState;
1404 const SetupProcessor::RoutinePointer &setupRoutine = draw.setupPointer;
1405
1406 int ms = state.multiSample;
1407 int pos = state.positionRegister;
1408 const DrawData *data = draw.data;
1409 int visible = 0;
1410
1411 for(int i = 0; i < count; i++, triangle++)
1412 {
1413 Vertex &v0 = triangle->v0;
1414 Vertex &v1 = triangle->v1;
1415 Vertex &v2 = triangle->v2;
1416
1417 if((v0.clipFlags & v1.clipFlags & v2.clipFlags) == Clipper::CLIP_FINITE)
1418 {
1419 Polygon polygon(&v0.v[pos], &v1.v[pos], &v2.v[pos]);
1420
1421 int clipFlagsOr = v0.clipFlags | v1.clipFlags | v2.clipFlags | draw.clipFlags;
1422
1423 if(clipFlagsOr != Clipper::CLIP_FINITE)
1424 {
1425 if(!renderer->clipper->clip(polygon, clipFlagsOr, draw))
1426 {
1427 continue;
1428 }
1429 }
1430
1431 if(setupRoutine(primitive, triangle, &polygon, data))
1432 {
1433 primitive += ms;
1434 visible++;
1435 }
1436 }
1437 }
1438
1439 return visible;
1440 }
1441
1442 int Renderer::setupWireframeTriangle(Renderer *renderer, int unit, int count)
1443 {
1444 Triangle *triangle = renderer->triangleBatch[unit];
1445 Primitive *primitive = renderer->primitiveBatch[unit];
1446 int visible = 0;
1447
1448 DrawCall &draw = *renderer->drawList[renderer->primitiveProgress[unit].drawCall % DRAW_COUNT];
1449 SetupProcessor::State &state = draw.setupState;
1450 SetupProcessor::RoutinePointer setupRoutine = draw.setupPointer;
1451
1452 const Vertex &v0 = triangle[0].v0;
1453 const Vertex &v1 = triangle[0].v1;
1454 const Vertex &v2 = triangle[0].v2;
1455
1456 float d = (v0.y * v1.x - v0.x * v1.y) * v2.w + (v0.x * v2.y - v0.y * v2.x) * v1.w + (v2.x * v1.y - v1.x * v2.y) * v0.w;
1457
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001458 if(state.cullMode == CULL_CLOCKWISE)
John Bauman89401822014-05-06 15:04:28 -04001459 {
1460 if(d >= 0) return 0;
1461 }
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001462 else if(state.cullMode == CULL_COUNTERCLOCKWISE)
John Bauman89401822014-05-06 15:04:28 -04001463 {
1464 if(d <= 0) return 0;
1465 }
1466
1467 // Copy attributes
1468 triangle[1].v0 = v1;
1469 triangle[1].v1 = v2;
1470 triangle[2].v0 = v2;
1471 triangle[2].v1 = v0;
1472
1473 if(state.color[0][0].flat) // FIXME
1474 {
1475 for(int i = 0; i < 2; i++)
1476 {
1477 triangle[1].v0.C[i] = triangle[0].v0.C[i];
John Bauman66b8ab22014-05-06 15:57:45 -04001478 triangle[1].v1.C[i] = triangle[0].v0.C[i];
John Bauman89401822014-05-06 15:04:28 -04001479 triangle[2].v0.C[i] = triangle[0].v0.C[i];
John Bauman66b8ab22014-05-06 15:57:45 -04001480 triangle[2].v1.C[i] = triangle[0].v0.C[i];
John Bauman89401822014-05-06 15:04:28 -04001481 }
1482 }
1483
1484 for(int i = 0; i < 3; i++)
1485 {
1486 if(setupLine(renderer, *primitive, *triangle, draw))
1487 {
1488 primitive->area = 0.5f * d;
1489
1490 primitive++;
1491 visible++;
1492 }
1493
1494 triangle++;
1495 }
1496
1497 return visible;
1498 }
1499
1500 int Renderer::setupVertexTriangle(Renderer *renderer, int unit, int count)
1501 {
1502 Triangle *triangle = renderer->triangleBatch[unit];
1503 Primitive *primitive = renderer->primitiveBatch[unit];
1504 int visible = 0;
1505
1506 DrawCall &draw = *renderer->drawList[renderer->primitiveProgress[unit].drawCall % DRAW_COUNT];
1507 SetupProcessor::State &state = draw.setupState;
1508
1509 const Vertex &v0 = triangle[0].v0;
1510 const Vertex &v1 = triangle[0].v1;
1511 const Vertex &v2 = triangle[0].v2;
1512
1513 float d = (v0.y * v1.x - v0.x * v1.y) * v2.w + (v0.x * v2.y - v0.y * v2.x) * v1.w + (v2.x * v1.y - v1.x * v2.y) * v0.w;
1514
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001515 if(state.cullMode == CULL_CLOCKWISE)
John Bauman89401822014-05-06 15:04:28 -04001516 {
1517 if(d >= 0) return 0;
1518 }
Nicolas Capensa0f4be82014-10-22 14:35:30 -04001519 else if(state.cullMode == CULL_COUNTERCLOCKWISE)
John Bauman89401822014-05-06 15:04:28 -04001520 {
1521 if(d <= 0) return 0;
1522 }
1523
1524 // Copy attributes
1525 triangle[1].v0 = v1;
1526 triangle[2].v0 = v2;
1527
1528 for(int i = 0; i < 3; i++)
1529 {
1530 if(setupPoint(renderer, *primitive, *triangle, draw))
1531 {
1532 primitive->area = 0.5f * d;
1533
1534 primitive++;
1535 visible++;
1536 }
1537
1538 triangle++;
1539 }
1540
1541 return visible;
1542 }
1543
1544 int Renderer::setupLines(Renderer *renderer, int unit, int count)
1545 {
1546 Triangle *triangle = renderer->triangleBatch[unit];
1547 Primitive *primitive = renderer->primitiveBatch[unit];
1548 int visible = 0;
1549
1550 DrawCall &draw = *renderer->drawList[renderer->primitiveProgress[unit].drawCall % DRAW_COUNT];
1551 SetupProcessor::State &state = draw.setupState;
1552
1553 int ms = state.multiSample;
1554
1555 for(int i = 0; i < count; i++)
1556 {
1557 if(setupLine(renderer, *primitive, *triangle, draw))
1558 {
1559 primitive += ms;
1560 visible++;
1561 }
1562
1563 triangle++;
1564 }
1565
1566 return visible;
1567 }
1568
1569 int Renderer::setupPoints(Renderer *renderer, int unit, int count)
1570 {
1571 Triangle *triangle = renderer->triangleBatch[unit];
1572 Primitive *primitive = renderer->primitiveBatch[unit];
1573 int visible = 0;
1574
1575 DrawCall &draw = *renderer->drawList[renderer->primitiveProgress[unit].drawCall % DRAW_COUNT];
1576 SetupProcessor::State &state = draw.setupState;
1577
1578 int ms = state.multiSample;
1579
1580 for(int i = 0; i < count; i++)
1581 {
1582 if(setupPoint(renderer, *primitive, *triangle, draw))
1583 {
1584 primitive += ms;
1585 visible++;
1586 }
1587
1588 triangle++;
1589 }
1590
1591 return visible;
1592 }
1593
1594 bool Renderer::setupLine(Renderer *renderer, Primitive &primitive, Triangle &triangle, const DrawCall &draw)
1595 {
1596 const SetupProcessor::RoutinePointer &setupRoutine = draw.setupPointer;
1597 const SetupProcessor::State &state = draw.setupState;
1598 const DrawData &data = *draw.data;
1599
Nicolas Capens235781d2015-01-27 01:46:53 -05001600 float lineWidth = data.lineWidth;
1601
John Bauman89401822014-05-06 15:04:28 -04001602 Vertex &v0 = triangle.v0;
1603 Vertex &v1 = triangle.v1;
1604
1605 int pos = state.positionRegister;
1606
1607 const float4 &P0 = v0.v[pos];
1608 const float4 &P1 = v1.v[pos];
1609
1610 if(P0.w <= 0 && P1.w <= 0)
1611 {
1612 return false;
1613 }
1614
John Bauman19bac1e2014-05-06 15:23:49 -04001615 const float W = data.Wx16[0] * (1.0f / 16.0f);
1616 const float H = data.Hx16[0] * (1.0f / 16.0f);
John Bauman89401822014-05-06 15:04:28 -04001617
1618 float dx = W * (P1.x / P1.w - P0.x / P0.w);
1619 float dy = H * (P1.y / P1.w - P0.y / P0.w);
1620
1621 if(dx == 0 && dy == 0)
1622 {
1623 return false;
1624 }
1625
1626 if(false) // Rectangle
1627 {
1628 float4 P[4];
1629 int C[4];
1630
1631 P[0] = P0;
1632 P[1] = P1;
1633 P[2] = P1;
1634 P[3] = P0;
1635
Nicolas Capens235781d2015-01-27 01:46:53 -05001636 float scale = lineWidth * 0.5f / sqrt(dx*dx + dy*dy);
John Bauman89401822014-05-06 15:04:28 -04001637
1638 dx *= scale;
1639 dy *= scale;
1640
1641 float dx0w = dx * P0.w / W;
1642 float dy0h = dy * P0.w / H;
1643 float dx0h = dx * P0.w / H;
1644 float dy0w = dy * P0.w / W;
1645
1646 float dx1w = dx * P1.w / W;
1647 float dy1h = dy * P1.w / H;
1648 float dx1h = dx * P1.w / H;
1649 float dy1w = dy * P1.w / W;
1650
John Bauman19bac1e2014-05-06 15:23:49 -04001651 P[0].x += -dy0w + -dx0w;
1652 P[0].y += -dx0h + +dy0h;
John Bauman89401822014-05-06 15:04:28 -04001653 C[0] = computeClipFlags(P[0], data);
1654
John Bauman19bac1e2014-05-06 15:23:49 -04001655 P[1].x += -dy1w + +dx1w;
John Bauman89401822014-05-06 15:04:28 -04001656 P[1].y += -dx1h + +dy1h;
1657 C[1] = computeClipFlags(P[1], data);
1658
John Bauman19bac1e2014-05-06 15:23:49 -04001659 P[2].x += +dy1w + +dx1w;
1660 P[2].y += +dx1h + -dy1h;
John Bauman89401822014-05-06 15:04:28 -04001661 C[2] = computeClipFlags(P[2], data);
1662
John Bauman19bac1e2014-05-06 15:23:49 -04001663 P[3].x += +dy0w + -dx0w;
1664 P[3].y += +dx0h + +dy0h;
John Bauman89401822014-05-06 15:04:28 -04001665 C[3] = computeClipFlags(P[3], data);
1666
1667 if((C[0] & C[1] & C[2] & C[3]) == Clipper::CLIP_FINITE)
1668 {
1669 Polygon polygon(P, 4);
1670
1671 int clipFlagsOr = C[0] | C[1] | C[2] | C[3] | draw.clipFlags;
1672
1673 if(clipFlagsOr != Clipper::CLIP_FINITE)
1674 {
1675 if(!renderer->clipper->clip(polygon, clipFlagsOr, draw))
1676 {
1677 return false;
1678 }
1679 }
1680
1681 return setupRoutine(&primitive, &triangle, &polygon, &data);
1682 }
1683 }
1684 else // Diamond test convention
1685 {
1686 float4 P[8];
1687 int C[8];
1688
1689 P[0] = P0;
1690 P[1] = P0;
1691 P[2] = P0;
1692 P[3] = P0;
1693 P[4] = P1;
1694 P[5] = P1;
1695 P[6] = P1;
1696 P[7] = P1;
1697
Nicolas Capens235781d2015-01-27 01:46:53 -05001698 float dx0 = lineWidth * 0.5f * P0.w / W;
1699 float dy0 = lineWidth * 0.5f * P0.w / H;
John Bauman89401822014-05-06 15:04:28 -04001700
Nicolas Capens235781d2015-01-27 01:46:53 -05001701 float dx1 = lineWidth * 0.5f * P1.w / W;
1702 float dy1 = lineWidth * 0.5f * P1.w / H;
John Bauman89401822014-05-06 15:04:28 -04001703
1704 P[0].x += -dx0;
1705 C[0] = computeClipFlags(P[0], data);
1706
John Bauman19bac1e2014-05-06 15:23:49 -04001707 P[1].y += +dy0;
John Bauman89401822014-05-06 15:04:28 -04001708 C[1] = computeClipFlags(P[1], data);
1709
1710 P[2].x += +dx0;
1711 C[2] = computeClipFlags(P[2], data);
1712
John Bauman19bac1e2014-05-06 15:23:49 -04001713 P[3].y += -dy0;
John Bauman89401822014-05-06 15:04:28 -04001714 C[3] = computeClipFlags(P[3], data);
1715
1716 P[4].x += -dx1;
1717 C[4] = computeClipFlags(P[4], data);
1718
John Bauman19bac1e2014-05-06 15:23:49 -04001719 P[5].y += +dy1;
John Bauman89401822014-05-06 15:04:28 -04001720 C[5] = computeClipFlags(P[5], data);
1721
1722 P[6].x += +dx1;
1723 C[6] = computeClipFlags(P[6], data);
1724
John Bauman19bac1e2014-05-06 15:23:49 -04001725 P[7].y += -dy1;
John Bauman89401822014-05-06 15:04:28 -04001726 C[7] = computeClipFlags(P[7], data);
1727
1728 if((C[0] & C[1] & C[2] & C[3] & C[4] & C[5] & C[6] & C[7]) == Clipper::CLIP_FINITE)
1729 {
1730 float4 L[6];
1731
John Bauman19bac1e2014-05-06 15:23:49 -04001732 if(dx > -dy)
John Bauman89401822014-05-06 15:04:28 -04001733 {
John Bauman19bac1e2014-05-06 15:23:49 -04001734 if(dx > dy) // Right
John Bauman89401822014-05-06 15:04:28 -04001735 {
1736 L[0] = P[0];
1737 L[1] = P[1];
1738 L[2] = P[5];
1739 L[3] = P[6];
1740 L[4] = P[7];
1741 L[5] = P[3];
1742 }
1743 else // Down
1744 {
1745 L[0] = P[0];
1746 L[1] = P[4];
1747 L[2] = P[5];
1748 L[3] = P[6];
1749 L[4] = P[2];
1750 L[5] = P[3];
1751 }
1752 }
1753 else
1754 {
John Bauman19bac1e2014-05-06 15:23:49 -04001755 if(dx > dy) // Up
John Bauman89401822014-05-06 15:04:28 -04001756 {
1757 L[0] = P[0];
1758 L[1] = P[1];
1759 L[2] = P[2];
1760 L[3] = P[6];
1761 L[4] = P[7];
1762 L[5] = P[4];
1763 }
1764 else // Left
1765 {
1766 L[0] = P[1];
1767 L[1] = P[2];
1768 L[2] = P[3];
1769 L[3] = P[7];
1770 L[4] = P[4];
1771 L[5] = P[5];
1772 }
1773 }
1774
1775 Polygon polygon(L, 6);
1776
1777 int clipFlagsOr = C[0] | C[1] | C[2] | C[3] | C[4] | C[5] | C[6] | C[7] | draw.clipFlags;
1778
1779 if(clipFlagsOr != Clipper::CLIP_FINITE)
1780 {
1781 if(!renderer->clipper->clip(polygon, clipFlagsOr, draw))
1782 {
1783 return false;
1784 }
1785 }
1786
1787 return setupRoutine(&primitive, &triangle, &polygon, &data);
1788 }
1789 }
1790
1791 return false;
1792 }
1793
1794 bool Renderer::setupPoint(Renderer *renderer, Primitive &primitive, Triangle &triangle, const DrawCall &draw)
1795 {
1796 const SetupProcessor::RoutinePointer &setupRoutine = draw.setupPointer;
1797 const SetupProcessor::State &state = draw.setupState;
1798 const DrawData &data = *draw.data;
1799
1800 Vertex &v = triangle.v0;
1801
1802 float pSize;
1803
1804 int pts = state.pointSizeRegister;
1805
1806 if(state.pointSizeRegister != 0xF)
1807 {
1808 pSize = v.v[pts].y;
1809 }
1810 else
1811 {
1812 pSize = data.point.pointSize[0];
1813 }
1814
1815 pSize = clamp(pSize, data.point.pointSizeMin, data.point.pointSizeMax);
1816
1817 float4 P[4];
1818 int C[4];
1819
1820 int pos = state.positionRegister;
1821
1822 P[0] = v.v[pos];
1823 P[1] = v.v[pos];
1824 P[2] = v.v[pos];
1825 P[3] = v.v[pos];
1826
John Bauman19bac1e2014-05-06 15:23:49 -04001827 const float X = pSize * P[0].w * data.halfPixelX[0];
1828 const float Y = pSize * P[0].w * data.halfPixelY[0];
John Bauman89401822014-05-06 15:04:28 -04001829
1830 P[0].x -= X;
John Bauman19bac1e2014-05-06 15:23:49 -04001831 P[0].y += Y;
John Bauman89401822014-05-06 15:04:28 -04001832 C[0] = computeClipFlags(P[0], data);
1833
1834 P[1].x += X;
John Bauman19bac1e2014-05-06 15:23:49 -04001835 P[1].y += Y;
John Bauman89401822014-05-06 15:04:28 -04001836 C[1] = computeClipFlags(P[1], data);
1837
1838 P[2].x += X;
John Bauman19bac1e2014-05-06 15:23:49 -04001839 P[2].y -= Y;
John Bauman89401822014-05-06 15:04:28 -04001840 C[2] = computeClipFlags(P[2], data);
1841
1842 P[3].x -= X;
John Bauman19bac1e2014-05-06 15:23:49 -04001843 P[3].y -= Y;
John Bauman89401822014-05-06 15:04:28 -04001844 C[3] = computeClipFlags(P[3], data);
1845
1846 triangle.v1 = triangle.v0;
1847 triangle.v2 = triangle.v0;
1848
1849 triangle.v1.X += iround(16 * 0.5f * pSize);
John Bauman19bac1e2014-05-06 15:23:49 -04001850 triangle.v2.Y -= iround(16 * 0.5f * pSize) * (data.Hx16[0] > 0.0f ? 1 : -1); // Both Direct3D and OpenGL expect (0, 0) in the top-left corner
John Bauman89401822014-05-06 15:04:28 -04001851
1852 Polygon polygon(P, 4);
1853
1854 if((C[0] & C[1] & C[2] & C[3]) == Clipper::CLIP_FINITE)
1855 {
1856 int clipFlagsOr = C[0] | C[1] | C[2] | C[3] | draw.clipFlags;
1857
1858 if(clipFlagsOr != Clipper::CLIP_FINITE)
1859 {
1860 if(!renderer->clipper->clip(polygon, clipFlagsOr, draw))
1861 {
1862 return false;
1863 }
1864 }
1865
1866 return setupRoutine(&primitive, &triangle, &polygon, &data);
1867 }
1868
1869 return false;
1870 }
1871
1872 unsigned int Renderer::computeClipFlags(const float4 &v, const DrawData &data)
1873 {
Nicolas Capens5491cb42015-07-02 15:33:29 -04001874 return ((v.x > v.w) << 0) |
1875 ((v.y > v.w) << 1) |
John Bauman89401822014-05-06 15:04:28 -04001876 ((v.z > v.w) << 2) |
Nicolas Capens5491cb42015-07-02 15:33:29 -04001877 ((v.x < -v.w) << 3) |
1878 ((v.y < -v.w) << 4) |
John Bauman89401822014-05-06 15:04:28 -04001879 ((v.z < 0) << 5) |
1880 Clipper::CLIP_FINITE; // FIXME: xyz finite
1881 }
1882
Nicolas Capens7381c992014-05-06 23:48:15 -04001883 void Renderer::initializeThreads()
John Bauman89401822014-05-06 15:04:28 -04001884 {
Nicolas Capens7381c992014-05-06 23:48:15 -04001885 unitCount = ceilPow2(threadCount);
1886 clusterCount = ceilPow2(threadCount);
John Bauman89401822014-05-06 15:04:28 -04001887
1888 for(int i = 0; i < unitCount; i++)
1889 {
1890 triangleBatch[i] = (Triangle*)allocate(batchSize * sizeof(Triangle));
1891 primitiveBatch[i] = (Primitive*)allocate(batchSize * sizeof(Primitive));
1892 }
1893
1894 for(int i = 0; i < threadCount; i++)
1895 {
1896 vertexTask[i] = (VertexTask*)allocate(sizeof(VertexTask));
1897 vertexTask[i]->vertexCache.drawCall = -1;
1898
1899 task[i].type = Task::SUSPEND;
1900
1901 resume[i] = new Event();
1902 suspend[i] = new Event();
1903
1904 Parameters parameters;
1905 parameters.threadIndex = i;
1906 parameters.renderer = this;
1907
1908 exitThreads = false;
1909 worker[i] = new Thread(threadFunction, &parameters);
1910
1911 suspend[i]->wait();
1912 suspend[i]->signal();
1913 }
1914 }
1915
1916 void Renderer::terminateThreads()
1917 {
1918 while(threadsAwake != 0)
1919 {
John Bauman19bac1e2014-05-06 15:23:49 -04001920 Thread::sleep(1);
John Bauman89401822014-05-06 15:04:28 -04001921 }
1922
1923 for(int thread = 0; thread < threadCount; thread++)
1924 {
1925 if(worker[thread])
1926 {
1927 exitThreads = true;
1928 resume[thread]->signal();
1929 worker[thread]->join();
1930
1931 delete worker[thread];
1932 worker[thread] = 0;
1933 delete resume[thread];
1934 resume[thread] = 0;
1935 delete suspend[thread];
1936 suspend[thread] = 0;
1937 }
1938
1939 deallocate(vertexTask[thread]);
1940 vertexTask[thread] = 0;
1941 }
John Bauman89401822014-05-06 15:04:28 -04001942
John Bauman89401822014-05-06 15:04:28 -04001943 for(int i = 0; i < 16; i++)
1944 {
1945 deallocate(triangleBatch[i]);
1946 triangleBatch[i] = 0;
1947
1948 deallocate(primitiveBatch[i]);
1949 primitiveBatch[i] = 0;
1950 }
1951 }
1952
1953 void Renderer::loadConstants(const VertexShader *vertexShader)
1954 {
1955 if(!vertexShader) return;
1956
Alexis Hetu8dcce862014-11-13 16:43:44 -05001957 size_t count = vertexShader->getLength();
John Bauman89401822014-05-06 15:04:28 -04001958
Alexis Hetu903e0252014-11-25 14:25:32 -05001959 for(size_t i = 0; i < count; i++)
John Bauman89401822014-05-06 15:04:28 -04001960 {
John Bauman19bac1e2014-05-06 15:23:49 -04001961 const Shader::Instruction *instruction = vertexShader->getInstruction(i);
John Bauman89401822014-05-06 15:04:28 -04001962
John Bauman19bac1e2014-05-06 15:23:49 -04001963 if(instruction->opcode == Shader::OPCODE_DEF)
John Bauman89401822014-05-06 15:04:28 -04001964 {
John Bauman19bac1e2014-05-06 15:23:49 -04001965 int index = instruction->dst.index;
John Bauman89401822014-05-06 15:04:28 -04001966 float value[4];
1967
John Bauman19bac1e2014-05-06 15:23:49 -04001968 value[0] = instruction->src[0].value[0];
1969 value[1] = instruction->src[0].value[1];
1970 value[2] = instruction->src[0].value[2];
1971 value[3] = instruction->src[0].value[3];
John Bauman89401822014-05-06 15:04:28 -04001972
1973 setVertexShaderConstantF(index, value);
1974 }
John Bauman19bac1e2014-05-06 15:23:49 -04001975 else if(instruction->opcode == Shader::OPCODE_DEFI)
John Bauman89401822014-05-06 15:04:28 -04001976 {
John Bauman19bac1e2014-05-06 15:23:49 -04001977 int index = instruction->dst.index;
John Bauman89401822014-05-06 15:04:28 -04001978 int integer[4];
1979
John Bauman19bac1e2014-05-06 15:23:49 -04001980 integer[0] = instruction->src[0].integer[0];
1981 integer[1] = instruction->src[0].integer[1];
1982 integer[2] = instruction->src[0].integer[2];
1983 integer[3] = instruction->src[0].integer[3];
John Bauman89401822014-05-06 15:04:28 -04001984
1985 setVertexShaderConstantI(index, integer);
1986 }
John Bauman19bac1e2014-05-06 15:23:49 -04001987 else if(instruction->opcode == Shader::OPCODE_DEFB)
John Bauman89401822014-05-06 15:04:28 -04001988 {
John Bauman19bac1e2014-05-06 15:23:49 -04001989 int index = instruction->dst.index;
1990 int boolean = instruction->src[0].boolean[0];
John Bauman89401822014-05-06 15:04:28 -04001991
1992 setVertexShaderConstantB(index, &boolean);
1993 }
1994 }
1995 }
1996
1997 void Renderer::loadConstants(const PixelShader *pixelShader)
1998 {
1999 if(!pixelShader) return;
2000
Alexis Hetu8dcce862014-11-13 16:43:44 -05002001 size_t count = pixelShader->getLength();
John Bauman89401822014-05-06 15:04:28 -04002002
Alexis Hetu903e0252014-11-25 14:25:32 -05002003 for(size_t i = 0; i < count; i++)
John Bauman89401822014-05-06 15:04:28 -04002004 {
John Bauman19bac1e2014-05-06 15:23:49 -04002005 const Shader::Instruction *instruction = pixelShader->getInstruction(i);
John Bauman89401822014-05-06 15:04:28 -04002006
John Bauman19bac1e2014-05-06 15:23:49 -04002007 if(instruction->opcode == Shader::OPCODE_DEF)
John Bauman89401822014-05-06 15:04:28 -04002008 {
John Bauman19bac1e2014-05-06 15:23:49 -04002009 int index = instruction->dst.index;
John Bauman89401822014-05-06 15:04:28 -04002010 float value[4];
2011
John Bauman19bac1e2014-05-06 15:23:49 -04002012 value[0] = instruction->src[0].value[0];
2013 value[1] = instruction->src[0].value[1];
2014 value[2] = instruction->src[0].value[2];
2015 value[3] = instruction->src[0].value[3];
John Bauman89401822014-05-06 15:04:28 -04002016
2017 setPixelShaderConstantF(index, value);
2018 }
John Bauman19bac1e2014-05-06 15:23:49 -04002019 else if(instruction->opcode == Shader::OPCODE_DEFI)
John Bauman89401822014-05-06 15:04:28 -04002020 {
John Bauman19bac1e2014-05-06 15:23:49 -04002021 int index = instruction->dst.index;
John Bauman89401822014-05-06 15:04:28 -04002022 int integer[4];
2023
John Bauman19bac1e2014-05-06 15:23:49 -04002024 integer[0] = instruction->src[0].integer[0];
2025 integer[1] = instruction->src[0].integer[1];
2026 integer[2] = instruction->src[0].integer[2];
2027 integer[3] = instruction->src[0].integer[3];
John Bauman89401822014-05-06 15:04:28 -04002028
2029 setPixelShaderConstantI(index, integer);
2030 }
John Bauman19bac1e2014-05-06 15:23:49 -04002031 else if(instruction->opcode == Shader::OPCODE_DEFB)
John Bauman89401822014-05-06 15:04:28 -04002032 {
John Bauman19bac1e2014-05-06 15:23:49 -04002033 int index = instruction->dst.index;
2034 int boolean = instruction->src[0].boolean[0];
John Bauman89401822014-05-06 15:04:28 -04002035
2036 setPixelShaderConstantB(index, &boolean);
2037 }
2038 }
2039 }
2040
2041 void Renderer::setIndexBuffer(Resource *indexBuffer)
2042 {
2043 context->indexBuffer = indexBuffer;
2044 }
2045
2046 void Renderer::setMultiSampleMask(unsigned int mask)
2047 {
2048 context->sampleMask = mask;
2049 }
2050
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002051 void Renderer::setTransparencyAntialiasing(TransparencyAntialiasing transparencyAntialiasing)
John Bauman89401822014-05-06 15:04:28 -04002052 {
2053 sw::transparencyAntialiasing = transparencyAntialiasing;
2054 }
2055
2056 bool Renderer::isReadWriteTexture(int sampler)
2057 {
Alexis Hetu1edcd8b2015-11-05 11:12:41 -05002058 for(int index = 0; index < RENDERTARGETS; index++)
John Bauman89401822014-05-06 15:04:28 -04002059 {
2060 if(context->renderTarget[index] && context->texture[sampler] == context->renderTarget[index]->getResource())
2061 {
2062 return true;
2063 }
2064 }
2065
2066 if(context->depthStencil && context->texture[sampler] == context->depthStencil->getResource())
2067 {
2068 return true;
2069 }
2070
2071 return false;
2072 }
2073
2074 void Renderer::updateClipper()
2075 {
2076 if(updateClipPlanes)
2077 {
John Bauman89401822014-05-06 15:04:28 -04002078 if(VertexProcessor::isFixedFunction()) // User plane in world space
2079 {
John Bauman19bac1e2014-05-06 15:23:49 -04002080 const Matrix &scissorWorld = getViewTransform();
John Bauman89401822014-05-06 15:04:28 -04002081
2082 if(clipFlags & Clipper::CLIP_PLANE0) clipPlane[0] = scissorWorld * userPlane[0];
2083 if(clipFlags & Clipper::CLIP_PLANE1) clipPlane[1] = scissorWorld * userPlane[1];
2084 if(clipFlags & Clipper::CLIP_PLANE2) clipPlane[2] = scissorWorld * userPlane[2];
2085 if(clipFlags & Clipper::CLIP_PLANE3) clipPlane[3] = scissorWorld * userPlane[3];
2086 if(clipFlags & Clipper::CLIP_PLANE4) clipPlane[4] = scissorWorld * userPlane[4];
2087 if(clipFlags & Clipper::CLIP_PLANE5) clipPlane[5] = scissorWorld * userPlane[5];
2088 }
2089 else // User plane in clip space
2090 {
John Bauman19bac1e2014-05-06 15:23:49 -04002091 if(clipFlags & Clipper::CLIP_PLANE0) clipPlane[0] = userPlane[0];
2092 if(clipFlags & Clipper::CLIP_PLANE1) clipPlane[1] = userPlane[1];
2093 if(clipFlags & Clipper::CLIP_PLANE2) clipPlane[2] = userPlane[2];
2094 if(clipFlags & Clipper::CLIP_PLANE3) clipPlane[3] = userPlane[3];
2095 if(clipFlags & Clipper::CLIP_PLANE4) clipPlane[4] = userPlane[4];
2096 if(clipFlags & Clipper::CLIP_PLANE5) clipPlane[5] = userPlane[5];
John Bauman89401822014-05-06 15:04:28 -04002097 }
2098
2099 updateClipPlanes = false;
2100 }
2101 }
2102
2103 void Renderer::setTextureResource(unsigned int sampler, Resource *resource)
2104 {
Alexis Hetu0b65c5e2015-03-31 11:48:57 -04002105 ASSERT(sampler < TOTAL_IMAGE_UNITS);
John Bauman89401822014-05-06 15:04:28 -04002106
2107 context->texture[sampler] = resource;
2108 }
2109
2110 void Renderer::setTextureLevel(unsigned int sampler, unsigned int face, unsigned int level, Surface *surface, TextureType type)
2111 {
Alexis Hetu0b65c5e2015-03-31 11:48:57 -04002112 ASSERT(sampler < TOTAL_IMAGE_UNITS && face < 6 && level < MIPMAP_LEVELS);
John Bauman89401822014-05-06 15:04:28 -04002113
2114 context->sampler[sampler].setTextureLevel(face, level, surface, type);
2115 }
2116
2117 void Renderer::setTextureFilter(SamplerType type, int sampler, FilterType textureFilter)
2118 {
2119 if(type == SAMPLER_PIXEL)
2120 {
2121 PixelProcessor::setTextureFilter(sampler, textureFilter);
2122 }
2123 else
2124 {
2125 VertexProcessor::setTextureFilter(sampler, textureFilter);
2126 }
2127 }
2128
2129 void Renderer::setMipmapFilter(SamplerType type, int sampler, MipmapType mipmapFilter)
2130 {
2131 if(type == SAMPLER_PIXEL)
2132 {
2133 PixelProcessor::setMipmapFilter(sampler, mipmapFilter);
2134 }
2135 else
2136 {
2137 VertexProcessor::setMipmapFilter(sampler, mipmapFilter);
2138 }
2139 }
2140
2141 void Renderer::setGatherEnable(SamplerType type, int sampler, bool enable)
2142 {
2143 if(type == SAMPLER_PIXEL)
2144 {
2145 PixelProcessor::setGatherEnable(sampler, enable);
2146 }
2147 else
2148 {
2149 VertexProcessor::setGatherEnable(sampler, enable);
2150 }
2151 }
2152
2153 void Renderer::setAddressingModeU(SamplerType type, int sampler, AddressingMode addressMode)
2154 {
2155 if(type == SAMPLER_PIXEL)
2156 {
2157 PixelProcessor::setAddressingModeU(sampler, addressMode);
2158 }
2159 else
2160 {
2161 VertexProcessor::setAddressingModeU(sampler, addressMode);
2162 }
2163 }
2164
2165 void Renderer::setAddressingModeV(SamplerType type, int sampler, AddressingMode addressMode)
2166 {
2167 if(type == SAMPLER_PIXEL)
2168 {
2169 PixelProcessor::setAddressingModeV(sampler, addressMode);
2170 }
2171 else
2172 {
2173 VertexProcessor::setAddressingModeV(sampler, addressMode);
2174 }
2175 }
2176
2177 void Renderer::setAddressingModeW(SamplerType type, int sampler, AddressingMode addressMode)
2178 {
2179 if(type == SAMPLER_PIXEL)
2180 {
2181 PixelProcessor::setAddressingModeW(sampler, addressMode);
2182 }
2183 else
2184 {
2185 VertexProcessor::setAddressingModeW(sampler, addressMode);
2186 }
2187 }
2188
2189 void Renderer::setReadSRGB(SamplerType type, int sampler, bool sRGB)
2190 {
2191 if(type == SAMPLER_PIXEL)
2192 {
2193 PixelProcessor::setReadSRGB(sampler, sRGB);
2194 }
2195 else
2196 {
2197 VertexProcessor::setReadSRGB(sampler, sRGB);
2198 }
2199 }
2200
2201 void Renderer::setMipmapLOD(SamplerType type, int sampler, float bias)
2202 {
2203 if(type == SAMPLER_PIXEL)
2204 {
2205 PixelProcessor::setMipmapLOD(sampler, bias);
2206 }
2207 else
2208 {
2209 VertexProcessor::setMipmapLOD(sampler, bias);
2210 }
2211 }
2212
2213 void Renderer::setBorderColor(SamplerType type, int sampler, const Color<float> &borderColor)
2214 {
2215 if(type == SAMPLER_PIXEL)
2216 {
2217 PixelProcessor::setBorderColor(sampler, borderColor);
2218 }
2219 else
2220 {
2221 VertexProcessor::setBorderColor(sampler, borderColor);
2222 }
2223 }
2224
Alexis Hetu617a5d52014-11-13 10:56:20 -05002225 void Renderer::setMaxAnisotropy(SamplerType type, int sampler, float maxAnisotropy)
John Bauman89401822014-05-06 15:04:28 -04002226 {
2227 if(type == SAMPLER_PIXEL)
2228 {
2229 PixelProcessor::setMaxAnisotropy(sampler, maxAnisotropy);
2230 }
2231 else
2232 {
2233 VertexProcessor::setMaxAnisotropy(sampler, maxAnisotropy);
2234 }
2235 }
2236
Alexis Hetu1d01aa32015-09-29 11:50:05 -04002237 void Renderer::setSwizzleR(SamplerType type, int sampler, SwizzleType swizzleR)
2238 {
2239 if(type == SAMPLER_PIXEL)
2240 {
2241 PixelProcessor::setSwizzleR(sampler, swizzleR);
2242 }
2243 else
2244 {
2245 VertexProcessor::setSwizzleR(sampler, swizzleR);
2246 }
2247 }
2248
2249 void Renderer::setSwizzleG(SamplerType type, int sampler, SwizzleType swizzleG)
2250 {
2251 if(type == SAMPLER_PIXEL)
2252 {
2253 PixelProcessor::setSwizzleG(sampler, swizzleG);
2254 }
2255 else
2256 {
2257 VertexProcessor::setSwizzleG(sampler, swizzleG);
2258 }
2259 }
2260
2261 void Renderer::setSwizzleB(SamplerType type, int sampler, SwizzleType swizzleB)
2262 {
2263 if(type == SAMPLER_PIXEL)
2264 {
2265 PixelProcessor::setSwizzleB(sampler, swizzleB);
2266 }
2267 else
2268 {
2269 VertexProcessor::setSwizzleB(sampler, swizzleB);
2270 }
2271 }
2272
2273 void Renderer::setSwizzleA(SamplerType type, int sampler, SwizzleType swizzleA)
2274 {
2275 if(type == SAMPLER_PIXEL)
2276 {
2277 PixelProcessor::setSwizzleA(sampler, swizzleA);
2278 }
2279 else
2280 {
2281 VertexProcessor::setSwizzleA(sampler, swizzleA);
2282 }
2283 }
2284
John Bauman89401822014-05-06 15:04:28 -04002285 void Renderer::setPointSpriteEnable(bool pointSpriteEnable)
2286 {
2287 context->setPointSpriteEnable(pointSpriteEnable);
2288 }
2289
2290 void Renderer::setPointScaleEnable(bool pointScaleEnable)
2291 {
2292 context->setPointScaleEnable(pointScaleEnable);
2293 }
2294
Nicolas Capens235781d2015-01-27 01:46:53 -05002295 void Renderer::setLineWidth(float width)
2296 {
2297 context->lineWidth = width;
2298 }
2299
John Bauman89401822014-05-06 15:04:28 -04002300 void Renderer::setDepthBias(float bias)
2301 {
2302 depthBias = bias;
2303 }
2304
2305 void Renderer::setSlopeDepthBias(float slopeBias)
2306 {
2307 slopeDepthBias = slopeBias;
2308 }
2309
2310 void Renderer::setPixelShader(const PixelShader *shader)
2311 {
2312 context->pixelShader = shader;
2313
2314 loadConstants(shader);
2315 }
2316
2317 void Renderer::setVertexShader(const VertexShader *shader)
2318 {
2319 context->vertexShader = shader;
2320
2321 loadConstants(shader);
2322 }
2323
2324 void Renderer::setPixelShaderConstantF(int index, const float value[4], int count)
2325 {
2326 for(int i = 0; i < DRAW_COUNT; i++)
2327 {
2328 if(drawCall[i]->psDirtyConstF < index + count)
2329 {
2330 drawCall[i]->psDirtyConstF = index + count;
2331 }
2332 }
2333
2334 for(int i = 0; i < count; i++)
2335 {
2336 PixelProcessor::setFloatConstant(index + i, value);
2337 value += 4;
2338 }
2339 }
2340
2341 void Renderer::setPixelShaderConstantI(int index, const int value[4], int count)
2342 {
2343 for(int i = 0; i < DRAW_COUNT; i++)
2344 {
2345 if(drawCall[i]->psDirtyConstI < index + count)
2346 {
2347 drawCall[i]->psDirtyConstI = index + count;
2348 }
2349 }
2350
2351 for(int i = 0; i < count; i++)
2352 {
2353 PixelProcessor::setIntegerConstant(index + i, value);
2354 value += 4;
2355 }
2356 }
2357
2358 void Renderer::setPixelShaderConstantB(int index, const int *boolean, int count)
2359 {
2360 for(int i = 0; i < DRAW_COUNT; i++)
2361 {
2362 if(drawCall[i]->psDirtyConstB < index + count)
2363 {
2364 drawCall[i]->psDirtyConstB = index + count;
2365 }
2366 }
2367
2368 for(int i = 0; i < count; i++)
2369 {
2370 PixelProcessor::setBooleanConstant(index + i, *boolean);
2371 boolean++;
2372 }
2373 }
2374
2375 void Renderer::setVertexShaderConstantF(int index, const float value[4], int count)
2376 {
2377 for(int i = 0; i < DRAW_COUNT; i++)
2378 {
2379 if(drawCall[i]->vsDirtyConstF < index + count)
2380 {
2381 drawCall[i]->vsDirtyConstF = index + count;
2382 }
2383 }
2384
2385 for(int i = 0; i < count; i++)
2386 {
2387 VertexProcessor::setFloatConstant(index + i, value);
2388 value += 4;
2389 }
2390 }
2391
2392 void Renderer::setVertexShaderConstantI(int index, const int value[4], int count)
2393 {
2394 for(int i = 0; i < DRAW_COUNT; i++)
2395 {
2396 if(drawCall[i]->vsDirtyConstI < index + count)
2397 {
2398 drawCall[i]->vsDirtyConstI = index + count;
2399 }
2400 }
2401
2402 for(int i = 0; i < count; i++)
2403 {
2404 VertexProcessor::setIntegerConstant(index + i, value);
2405 value += 4;
2406 }
2407 }
2408
2409 void Renderer::setVertexShaderConstantB(int index, const int *boolean, int count)
2410 {
2411 for(int i = 0; i < DRAW_COUNT; i++)
2412 {
2413 if(drawCall[i]->vsDirtyConstB < index + count)
2414 {
2415 drawCall[i]->vsDirtyConstB = index + count;
2416 }
2417 }
2418
2419 for(int i = 0; i < count; i++)
2420 {
2421 VertexProcessor::setBooleanConstant(index + i, *boolean);
2422 boolean++;
2423 }
2424 }
2425
2426 void Renderer::setModelMatrix(const Matrix &M, int i)
2427 {
2428 VertexProcessor::setModelMatrix(M, i);
2429 }
2430
2431 void Renderer::setViewMatrix(const Matrix &V)
2432 {
2433 VertexProcessor::setViewMatrix(V);
2434 updateClipPlanes = true;
2435 }
2436
2437 void Renderer::setBaseMatrix(const Matrix &B)
2438 {
2439 VertexProcessor::setBaseMatrix(B);
2440 updateClipPlanes = true;
2441 }
2442
2443 void Renderer::setProjectionMatrix(const Matrix &P)
2444 {
2445 VertexProcessor::setProjectionMatrix(P);
2446 updateClipPlanes = true;
2447 }
2448
John Bauman89401822014-05-06 15:04:28 -04002449 void Renderer::addQuery(Query *query)
2450 {
2451 queries.push_back(query);
2452 }
2453
2454 void Renderer::removeQuery(Query *query)
2455 {
2456 queries.remove(query);
2457 }
2458
2459 #if PERF_HUD
2460 int Renderer::getThreadCount()
2461 {
2462 return threadCount;
2463 }
2464
2465 int64_t Renderer::getVertexTime(int thread)
2466 {
2467 return vertexTime[thread];
2468 }
2469
2470 int64_t Renderer::getSetupTime(int thread)
2471 {
2472 return setupTime[thread];
2473 }
2474
2475 int64_t Renderer::getPixelTime(int thread)
2476 {
2477 return pixelTime[thread];
2478 }
2479
2480 void Renderer::resetTimers()
2481 {
2482 for(int thread = 0; thread < threadCount; thread++)
2483 {
2484 vertexTime[thread] = 0;
2485 setupTime[thread] = 0;
2486 pixelTime[thread] = 0;
2487 }
2488 }
2489 #endif
2490
2491 void Renderer::setViewport(const Viewport &viewport)
2492 {
2493 this->viewport = viewport;
2494 }
2495
John Bauman19bac1e2014-05-06 15:23:49 -04002496 void Renderer::setScissor(const Rect &scissor)
2497 {
2498 this->scissor = scissor;
2499 }
2500
John Bauman89401822014-05-06 15:04:28 -04002501 void Renderer::setClipFlags(int flags)
2502 {
2503 clipFlags = flags << 8; // Bottom 8 bits used by legacy frustum
2504 }
2505
2506 void Renderer::setClipPlane(unsigned int index, const float plane[4])
2507 {
Nicolas Capensd2264142015-07-02 17:06:53 -04002508 if(index < MAX_CLIP_PLANES)
John Bauman89401822014-05-06 15:04:28 -04002509 {
2510 userPlane[index] = plane;
2511 }
2512 else ASSERT(false);
2513
2514 updateClipPlanes = true;
2515 }
2516
2517 void Renderer::updateConfiguration(bool initialUpdate)
2518 {
2519 bool newConfiguration = swiftConfig->hasNewConfiguration();
2520
2521 if(newConfiguration || initialUpdate)
2522 {
2523 terminateThreads();
2524
2525 SwiftConfig::Configuration configuration = {0};
2526 swiftConfig->getConfiguration(configuration);
2527
John Bauman66b8ab22014-05-06 15:57:45 -04002528 precacheVertex = !newConfiguration && configuration.precache;
2529 precacheSetup = !newConfiguration && configuration.precache;
2530 precachePixel = !newConfiguration && configuration.precache;
2531
John Bauman89401822014-05-06 15:04:28 -04002532 VertexProcessor::setRoutineCacheSize(configuration.vertexRoutineCacheSize);
2533 PixelProcessor::setRoutineCacheSize(configuration.pixelRoutineCacheSize);
2534 SetupProcessor::setRoutineCacheSize(configuration.setupRoutineCacheSize);
2535
2536 switch(configuration.textureSampleQuality)
2537 {
Nicolas Capens7381c992014-05-06 23:48:15 -04002538 case 0: Sampler::setFilterQuality(FILTER_POINT); break;
2539 case 1: Sampler::setFilterQuality(FILTER_LINEAR); break;
2540 case 2: Sampler::setFilterQuality(FILTER_ANISOTROPIC); break;
2541 default: Sampler::setFilterQuality(FILTER_ANISOTROPIC); break;
John Bauman89401822014-05-06 15:04:28 -04002542 }
2543
2544 switch(configuration.mipmapQuality)
2545 {
2546 case 0: Sampler::setMipmapQuality(MIPMAP_POINT); break;
2547 case 1: Sampler::setMipmapQuality(MIPMAP_LINEAR); break;
Nicolas Capens7381c992014-05-06 23:48:15 -04002548 default: Sampler::setMipmapQuality(MIPMAP_LINEAR); break;
John Bauman89401822014-05-06 15:04:28 -04002549 }
2550
2551 setPerspectiveCorrection(configuration.perspectiveCorrection);
2552
2553 switch(configuration.transcendentalPrecision)
2554 {
2555 case 0:
2556 logPrecision = APPROXIMATE;
2557 expPrecision = APPROXIMATE;
2558 rcpPrecision = APPROXIMATE;
2559 rsqPrecision = APPROXIMATE;
2560 break;
2561 case 1:
2562 logPrecision = PARTIAL;
2563 expPrecision = PARTIAL;
2564 rcpPrecision = PARTIAL;
2565 rsqPrecision = PARTIAL;
2566 break;
2567 case 2:
2568 logPrecision = ACCURATE;
2569 expPrecision = ACCURATE;
2570 rcpPrecision = ACCURATE;
2571 rsqPrecision = ACCURATE;
2572 break;
2573 case 3:
2574 logPrecision = WHQL;
2575 expPrecision = WHQL;
2576 rcpPrecision = WHQL;
2577 rsqPrecision = WHQL;
2578 break;
2579 case 4:
2580 logPrecision = IEEE;
2581 expPrecision = IEEE;
2582 rcpPrecision = IEEE;
2583 rsqPrecision = IEEE;
2584 break;
2585 default:
2586 logPrecision = ACCURATE;
2587 expPrecision = ACCURATE;
2588 rcpPrecision = ACCURATE;
2589 rsqPrecision = ACCURATE;
2590 break;
2591 }
2592
2593 switch(configuration.transparencyAntialiasing)
2594 {
Nicolas Capensa0f4be82014-10-22 14:35:30 -04002595 case 0: transparencyAntialiasing = TRANSPARENCY_NONE; break;
2596 case 1: transparencyAntialiasing = TRANSPARENCY_ALPHA_TO_COVERAGE; break;
2597 default: transparencyAntialiasing = TRANSPARENCY_NONE; break;
John Bauman89401822014-05-06 15:04:28 -04002598 }
2599
2600 switch(configuration.threadCount)
2601 {
Nicolas Capens7381c992014-05-06 23:48:15 -04002602 case -1: threadCount = CPUID::coreCount(); break;
2603 case 0: threadCount = CPUID::processAffinity(); break;
2604 default: threadCount = configuration.threadCount; break;
John Bauman89401822014-05-06 15:04:28 -04002605 }
2606
2607 CPUID::setEnableSSE4_1(configuration.enableSSE4_1);
2608 CPUID::setEnableSSSE3(configuration.enableSSSE3);
2609 CPUID::setEnableSSE3(configuration.enableSSE3);
2610 CPUID::setEnableSSE2(configuration.enableSSE2);
2611 CPUID::setEnableSSE(configuration.enableSSE);
2612
2613 for(int pass = 0; pass < 10; pass++)
2614 {
2615 optimization[pass] = configuration.optimization[pass];
2616 }
2617
2618 forceWindowed = configuration.forceWindowed;
2619 complementaryDepthBuffer = configuration.complementaryDepthBuffer;
2620 postBlendSRGB = configuration.postBlendSRGB;
2621 exactColorRounding = configuration.exactColorRounding;
2622 forceClearRegisters = configuration.forceClearRegisters;
2623
2624 #ifndef NDEBUG
2625 minPrimitives = configuration.minPrimitives;
2626 maxPrimitives = configuration.maxPrimitives;
2627 #endif
2628 }
Nicolas Capens7381c992014-05-06 23:48:15 -04002629
2630 if(!initialUpdate && !worker[0])
2631 {
2632 initializeThreads();
2633 }
John Bauman89401822014-05-06 15:04:28 -04002634 }
John Bauman89401822014-05-06 15:04:28 -04002635}