1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "Context.hpp"
16 
17 #include "PixelShader.hpp"
18 #include "VertexShader.hpp"
19 #include "Primitive.hpp"
20 #include "Surface.hpp"
21 #include "Memory.hpp"
22 #include "CPUID.hpp"
23 #include "Debug.hpp"
24 
25 #include <string.h>
26 
27 namespace sw
28 {
29 	extern bool perspectiveCorrection;
30 
31 	bool halfIntegerCoordinates = false;     // Pixel centers are not at integer coordinates
32 	bool symmetricNormalizedDepth = false;   // [-1, 1] instead of [0, 1]
33 	bool booleanFaceRegister = false;
34 	bool fullPixelPositionRegister = false;
35 	bool leadingVertexFirst = false;         // Flat shading uses first vertex, else last
36 	bool secondaryColor = false;             // Specular lighting is applied after texturing
37 
38 	bool forceWindowed = false;
39 	bool quadLayoutEnabled = false;
40 	bool veryEarlyDepthTest = true;
41 	bool complementaryDepthBuffer = false;
42 	bool postBlendSRGB = false;
43 	bool exactColorRounding = false;
44 	TransparencyAntialiasing transparencyAntialiasing = TRANSPARENCY_NONE;
45 	bool forceClearRegisters = false;
46 
Context()47 	Context::Context()
48 	{
49 		init();
50 	}
51 
~Context()52 	Context::~Context()
53 	{
54 	}
55 
operator new(size_t bytes)56 	void *Context::operator new(size_t bytes)
57 	{
58 		return allocate((unsigned int)bytes);
59 	}
60 
operator delete(void * pointer,size_t bytes)61 	void Context::operator delete(void *pointer, size_t bytes)
62 	{
63 		deallocate(pointer);
64 	}
65 
isDrawPoint(bool fillModeAware) const66 	bool Context::isDrawPoint(bool fillModeAware) const
67 	{
68 		switch(drawType)
69 		{
70 		case DRAW_POINTLIST:
71 		case DRAW_INDEXEDPOINTLIST8:
72 		case DRAW_INDEXEDPOINTLIST16:
73 		case DRAW_INDEXEDPOINTLIST32:
74 			return true;
75 		case DRAW_LINELIST:
76 		case DRAW_LINESTRIP:
77 		case DRAW_LINELOOP:
78 		case DRAW_INDEXEDLINELIST8:
79 		case DRAW_INDEXEDLINESTRIP8:
80 		case DRAW_INDEXEDLINELOOP8:
81 		case DRAW_INDEXEDLINELIST16:
82 		case DRAW_INDEXEDLINESTRIP16:
83 		case DRAW_INDEXEDLINELOOP16:
84 		case DRAW_INDEXEDLINELIST32:
85 		case DRAW_INDEXEDLINESTRIP32:
86 		case DRAW_INDEXEDLINELOOP32:
87 			return false;
88 		case DRAW_TRIANGLELIST:
89 		case DRAW_TRIANGLESTRIP:
90 		case DRAW_TRIANGLEFAN:
91 		case DRAW_INDEXEDTRIANGLELIST8:
92 		case DRAW_INDEXEDTRIANGLESTRIP8:
93 		case DRAW_INDEXEDTRIANGLEFAN8:
94 		case DRAW_INDEXEDTRIANGLELIST16:
95 		case DRAW_INDEXEDTRIANGLESTRIP16:
96 		case DRAW_INDEXEDTRIANGLEFAN16:
97 		case DRAW_INDEXEDTRIANGLELIST32:
98 		case DRAW_INDEXEDTRIANGLESTRIP32:
99 		case DRAW_INDEXEDTRIANGLEFAN32:
100 			return fillModeAware ? fillMode == FILL_VERTEX : false;
101 		case DRAW_QUADLIST:
102 			return false;
103 		default:
104 			ASSERT(false);
105 		}
106 
107 		return false;
108 	}
109 
isDrawLine(bool fillModeAware) const110 	bool Context::isDrawLine(bool fillModeAware) const
111 	{
112 		switch(drawType)
113 		{
114 		case DRAW_POINTLIST:
115 		case DRAW_INDEXEDPOINTLIST8:
116 		case DRAW_INDEXEDPOINTLIST16:
117 		case DRAW_INDEXEDPOINTLIST32:
118 			return false;
119 		case DRAW_LINELIST:
120 		case DRAW_LINESTRIP:
121 		case DRAW_LINELOOP:
122 		case DRAW_INDEXEDLINELIST8:
123 		case DRAW_INDEXEDLINESTRIP8:
124 		case DRAW_INDEXEDLINELOOP8:
125 		case DRAW_INDEXEDLINELIST16:
126 		case DRAW_INDEXEDLINESTRIP16:
127 		case DRAW_INDEXEDLINELOOP16:
128 		case DRAW_INDEXEDLINELIST32:
129 		case DRAW_INDEXEDLINESTRIP32:
130 		case DRAW_INDEXEDLINELOOP32:
131 			return true;
132 		case DRAW_TRIANGLELIST:
133 		case DRAW_TRIANGLESTRIP:
134 		case DRAW_TRIANGLEFAN:
135 		case DRAW_INDEXEDTRIANGLELIST8:
136 		case DRAW_INDEXEDTRIANGLESTRIP8:
137 		case DRAW_INDEXEDTRIANGLEFAN8:
138 		case DRAW_INDEXEDTRIANGLELIST16:
139 		case DRAW_INDEXEDTRIANGLESTRIP16:
140 		case DRAW_INDEXEDTRIANGLEFAN16:
141 		case DRAW_INDEXEDTRIANGLELIST32:
142 		case DRAW_INDEXEDTRIANGLESTRIP32:
143 		case DRAW_INDEXEDTRIANGLEFAN32:
144 			return fillModeAware ? fillMode == FILL_WIREFRAME : false;
145 		case DRAW_QUADLIST:
146 			return false;
147 		default:
148 			ASSERT(false);
149 		}
150 
151 		return false;
152 	}
153 
isDrawTriangle(bool fillModeAware) const154 	bool Context::isDrawTriangle(bool fillModeAware) const
155 	{
156 		switch(drawType)
157 		{
158 		case DRAW_POINTLIST:
159 		case DRAW_INDEXEDPOINTLIST8:
160 		case DRAW_INDEXEDPOINTLIST16:
161 		case DRAW_INDEXEDPOINTLIST32:
162 			return false;
163 		case DRAW_LINELIST:
164 		case DRAW_LINESTRIP:
165 		case DRAW_LINELOOP:
166 		case DRAW_INDEXEDLINELIST8:
167 		case DRAW_INDEXEDLINESTRIP8:
168 		case DRAW_INDEXEDLINELOOP8:
169 		case DRAW_INDEXEDLINELIST16:
170 		case DRAW_INDEXEDLINESTRIP16:
171 		case DRAW_INDEXEDLINELOOP16:
172 		case DRAW_INDEXEDLINELIST32:
173 		case DRAW_INDEXEDLINESTRIP32:
174 		case DRAW_INDEXEDLINELOOP32:
175 			return false;
176 		case DRAW_TRIANGLELIST:
177 		case DRAW_TRIANGLESTRIP:
178 		case DRAW_TRIANGLEFAN:
179 		case DRAW_INDEXEDTRIANGLELIST8:
180 		case DRAW_INDEXEDTRIANGLESTRIP8:
181 		case DRAW_INDEXEDTRIANGLEFAN8:
182 		case DRAW_INDEXEDTRIANGLELIST16:
183 		case DRAW_INDEXEDTRIANGLESTRIP16:
184 		case DRAW_INDEXEDTRIANGLEFAN16:
185 		case DRAW_INDEXEDTRIANGLELIST32:
186 		case DRAW_INDEXEDTRIANGLESTRIP32:
187 		case DRAW_INDEXEDTRIANGLEFAN32:
188 			return fillModeAware ? fillMode == FILL_SOLID : true;
189 		case DRAW_QUADLIST:
190 			// Quads are broken up into triangles
191 			return fillModeAware ? fillMode == FILL_SOLID : true;
192 		default:
193 			ASSERT(false);
194 		}
195 
196 		return true;
197 	}
198 
init()199 	void Context::init()
200 	{
201 		for(int i = 0; i < 8; i++)
202 		{
203 			textureStage[i].init(i, &sampler[i], (i >= 1) ? &textureStage[i - 1] : 0);
204 		}
205 
206 		// Set vertex streams to null stream
207 		for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
208 		{
209 			input[i].defaults();
210 		}
211 
212 		fogStart = 0.0f;
213 		fogEnd = 1.0f;
214 
215 		for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++) textureWrap[i] = 0;
216 		for(int i = 0; i < 8; i++) texGen[i] = TEXGEN_PASSTHRU;
217 		for(int i = 0; i < 8; i++) textureTransformCount[i] = 0;
218 		for(int i = 0; i < 8; i++) textureTransformProject[i] = false;
219 		textureWrapActive = false;
220 		localViewer = true;
221 		normalizeNormals = false;
222 
223 		for(int i = 0; i < RENDERTARGETS; ++i)
224 		{
225 			renderTarget[i] = nullptr;
226 		}
227 		depthBuffer = nullptr;
228 		stencilBuffer = nullptr;
229 
230 		stencilEnable = false;
231 		stencilCompareMode = STENCIL_ALWAYS;
232 		stencilReference = 0;
233 		stencilMask = 0xFFFFFFFF;
234 		stencilFailOperation = OPERATION_KEEP;
235 		stencilPassOperation = OPERATION_KEEP;
236 		stencilZFailOperation = OPERATION_KEEP;
237 		stencilWriteMask = 0xFFFFFFFF;
238 
239 		twoSidedStencil = false;
240 		stencilCompareModeCCW = STENCIL_ALWAYS;
241 		stencilReferenceCCW = 0;
242 		stencilMaskCCW = 0xFFFFFFFF;
243 		stencilFailOperationCCW = OPERATION_KEEP;
244 		stencilPassOperationCCW = OPERATION_KEEP;
245 		stencilZFailOperationCCW = OPERATION_KEEP;
246 		stencilWriteMaskCCW = 0xFFFFFFFF;
247 
248 		setGlobalMipmapBias(0);
249 
250 		lightingEnable = true;
251 		specularEnable = false;
252 		for(int i = 0; i < 8; i++) lightEnable[i] = false;
253 		for(int i = 0; i < 8; i++) worldLightPosition[i] = 0;
254 
255 		alphaCompareMode = ALPHA_ALWAYS;
256 		alphaTestEnable = false;
257 		fillMode = FILL_SOLID;
258 		shadingMode = SHADING_GOURAUD;
259 
260 		rasterizerDiscard = false;
261 
262 		depthCompareMode = DEPTH_LESS;
263 		depthBufferEnable = true;
264 		depthWriteEnable = true;
265 
266 		alphaBlendEnable = false;
267 		sourceBlendFactorState = BLEND_ONE;
268 		destBlendFactorState = BLEND_ZERO;
269 		blendOperationState = BLENDOP_ADD;
270 
271 		separateAlphaBlendEnable = false;
272 		sourceBlendFactorStateAlpha = BLEND_ONE;
273 		destBlendFactorStateAlpha = BLEND_ZERO;
274 		blendOperationStateAlpha = BLENDOP_ADD;
275 
276 		cullMode = CULL_CLOCKWISE;
277 		alphaReference = 0.0f;
278 
279 		for(int i = 0; i < RENDERTARGETS; i++)
280 		{
281 			colorWriteMask[i] = 0x0000000F;
282 		}
283 
284 		ambientMaterialSource = MATERIAL_MATERIAL;
285 		diffuseMaterialSource = MATERIAL_COLOR1;
286 		specularMaterialSource = MATERIAL_COLOR2;
287 		emissiveMaterialSource = MATERIAL_MATERIAL;
288 		colorVertexEnable = true;
289 
290 		fogEnable = false;
291 		pixelFogMode = FOG_NONE;
292 		vertexFogMode = FOG_NONE;
293 		wBasedFog = false;
294 		rangeFogEnable = false;
295 
296 		indexedVertexBlendEnable = false;
297 		vertexBlendMatrixCount = 0;
298 
299 		pixelShader = 0;
300 		vertexShader = 0;
301 
302 		instanceID = 0;
303 
304 		occlusionEnabled = false;
305 		transformFeedbackQueryEnabled = false;
306 		transformFeedbackEnabled = 0;
307 
308 		pointSpriteEnable = false;
309 		pointScaleEnable = false;
310 		lineWidth = 1.0f;
311 
312 		writeSRGB = false;
313 		sampleMask = 0xFFFFFFFF;
314 
315 		colorLogicOpEnabled = false;
316 		logicalOperation = LOGICALOP_COPY;
317 	}
318 
exp2Bias()319 	const float &Context::exp2Bias()
320 	{
321 		return bias;
322 	}
323 
getLightPosition(int light)324 	const Point &Context::getLightPosition(int light)
325 	{
326 		return worldLightPosition[light];
327 	}
328 
setGlobalMipmapBias(float bias)329 	void Context::setGlobalMipmapBias(float bias)
330 	{
331 		this->bias = exp2(bias + 0.5f);
332 	}
333 
setLightingEnable(bool lightingEnable)334 	void Context::setLightingEnable(bool lightingEnable)
335 	{
336 		this->lightingEnable = lightingEnable;
337 	}
338 
setSpecularEnable(bool specularEnable)339 	void Context::setSpecularEnable(bool specularEnable)
340 	{
341 		Context::specularEnable = specularEnable;
342 	}
343 
setLightEnable(int light,bool lightEnable)344 	void Context::setLightEnable(int light, bool lightEnable)
345 	{
346 		Context::lightEnable[light] = lightEnable;
347 	}
348 
setLightPosition(int light,Point worldLightPosition)349 	void Context::setLightPosition(int light, Point worldLightPosition)
350 	{
351 		Context::worldLightPosition[light] = worldLightPosition;
352 	}
353 
setAmbientMaterialSource(MaterialSource ambientMaterialSource)354 	void Context::setAmbientMaterialSource(MaterialSource ambientMaterialSource)
355 	{
356 		Context::ambientMaterialSource = ambientMaterialSource;
357 	}
358 
setDiffuseMaterialSource(MaterialSource diffuseMaterialSource)359 	void Context::setDiffuseMaterialSource(MaterialSource diffuseMaterialSource)
360 	{
361 		Context::diffuseMaterialSource = diffuseMaterialSource;
362 	}
363 
setSpecularMaterialSource(MaterialSource specularMaterialSource)364 	void Context::setSpecularMaterialSource(MaterialSource specularMaterialSource)
365 	{
366 		Context::specularMaterialSource = specularMaterialSource;
367 	}
368 
setEmissiveMaterialSource(MaterialSource emissiveMaterialSource)369 	void Context::setEmissiveMaterialSource(MaterialSource emissiveMaterialSource)
370 	{
371 		Context::emissiveMaterialSource = emissiveMaterialSource;
372 	}
373 
setPointSpriteEnable(bool pointSpriteEnable)374 	void Context::setPointSpriteEnable(bool pointSpriteEnable)
375 	{
376 		Context::pointSpriteEnable = pointSpriteEnable;
377 	}
378 
setPointScaleEnable(bool pointScaleEnable)379 	void Context::setPointScaleEnable(bool pointScaleEnable)
380 	{
381 		Context::pointScaleEnable = pointScaleEnable;
382 	}
383 
setDepthBufferEnable(bool depthBufferEnable)384 	bool Context::setDepthBufferEnable(bool depthBufferEnable)
385 	{
386 		bool modified = (Context::depthBufferEnable != depthBufferEnable);
387 		Context::depthBufferEnable = depthBufferEnable;
388 		return modified;
389 	}
390 
setAlphaBlendEnable(bool alphaBlendEnable)391 	bool Context::setAlphaBlendEnable(bool alphaBlendEnable)
392 	{
393 		bool modified = (Context::alphaBlendEnable != alphaBlendEnable);
394 		Context::alphaBlendEnable = alphaBlendEnable;
395 		return modified;
396 	}
397 
setSourceBlendFactor(BlendFactor sourceBlendFactor)398 	bool Context::setSourceBlendFactor(BlendFactor sourceBlendFactor)
399 	{
400 		bool modified = (Context::sourceBlendFactorState != sourceBlendFactor);
401 		Context::sourceBlendFactorState = sourceBlendFactor;
402 		return modified;
403 	}
404 
setDestBlendFactor(BlendFactor destBlendFactor)405 	bool Context::setDestBlendFactor(BlendFactor destBlendFactor)
406 	{
407 		bool modified = (Context::destBlendFactorState != destBlendFactor);
408 		Context::destBlendFactorState = destBlendFactor;
409 		return modified;
410 	}
411 
setBlendOperation(BlendOperation blendOperation)412 	bool Context::setBlendOperation(BlendOperation blendOperation)
413 	{
414 		bool modified = (Context::blendOperationState != blendOperation);
415 		Context::blendOperationState = blendOperation;
416 		return modified;
417 	}
418 
setSeparateAlphaBlendEnable(bool separateAlphaBlendEnable)419 	bool Context::setSeparateAlphaBlendEnable(bool separateAlphaBlendEnable)
420 	{
421 		bool modified = (Context::separateAlphaBlendEnable != separateAlphaBlendEnable);
422 		Context::separateAlphaBlendEnable = separateAlphaBlendEnable;
423 		return modified;
424 	}
425 
setSourceBlendFactorAlpha(BlendFactor sourceBlendFactorAlpha)426 	bool Context::setSourceBlendFactorAlpha(BlendFactor sourceBlendFactorAlpha)
427 	{
428 		bool modified = (Context::sourceBlendFactorStateAlpha != sourceBlendFactorAlpha);
429 		Context::sourceBlendFactorStateAlpha = sourceBlendFactorAlpha;
430 		return modified;
431 	}
432 
setDestBlendFactorAlpha(BlendFactor destBlendFactorAlpha)433 	bool Context::setDestBlendFactorAlpha(BlendFactor destBlendFactorAlpha)
434 	{
435 		bool modified = (Context::destBlendFactorStateAlpha != destBlendFactorAlpha);
436 		Context::destBlendFactorStateAlpha = destBlendFactorAlpha;
437 		return modified;
438 	}
439 
setBlendOperationAlpha(BlendOperation blendOperationAlpha)440 	bool Context::setBlendOperationAlpha(BlendOperation blendOperationAlpha)
441 	{
442 		bool modified = (Context::blendOperationStateAlpha != blendOperationAlpha);
443 		Context::blendOperationStateAlpha = blendOperationAlpha;
444 		return modified;
445 	}
446 
setColorWriteMask(int index,int colorWriteMask)447 	bool Context::setColorWriteMask(int index, int colorWriteMask)
448 	{
449 		bool modified = (Context::colorWriteMask[index] != colorWriteMask);
450 		Context::colorWriteMask[index] = colorWriteMask;
451 		return modified;
452 	}
453 
setWriteSRGB(bool sRGB)454 	bool Context::setWriteSRGB(bool sRGB)
455 	{
456 		bool modified = (Context::writeSRGB != sRGB);
457 		Context::writeSRGB = sRGB;
458 		return modified;
459 	}
460 
setColorLogicOpEnabled(bool enabled)461 	bool Context::setColorLogicOpEnabled(bool enabled)
462 	{
463 		bool modified = (Context::colorLogicOpEnabled != enabled);
464 		Context::colorLogicOpEnabled = enabled;
465 		return modified;
466 	}
467 
setLogicalOperation(LogicalOperation logicalOperation)468 	bool Context::setLogicalOperation(LogicalOperation logicalOperation)
469 	{
470 		bool modified = (Context::logicalOperation != logicalOperation);
471 		Context::logicalOperation = logicalOperation;
472 		return modified;
473 	}
474 
setColorVertexEnable(bool colorVertexEnable)475 	void Context::setColorVertexEnable(bool colorVertexEnable)
476 	{
477 		Context::colorVertexEnable = colorVertexEnable;
478 	}
479 
fogActive()480 	bool Context::fogActive()
481 	{
482 		if(!colorUsed()) return false;
483 
484 		if(pixelShaderVersion() >= 0x0300) return false;
485 
486 		return fogEnable;
487 	}
488 
pointSizeActive()489 	bool Context::pointSizeActive()
490 	{
491 		if(vertexShader)
492 		{
493 			return false;
494 		}
495 
496 		return isDrawPoint(true) && (input[PointSize] || (!preTransformed && pointScaleActive()));
497 	}
498 
pixelFogActive()499 	FogMode Context::pixelFogActive()
500 	{
501 		if(fogActive())
502 		{
503 			return pixelFogMode;
504 		}
505 
506 		return FOG_NONE;
507 	}
508 
depthWriteActive()509 	bool Context::depthWriteActive()
510 	{
511 		if(!depthBufferActive()) return false;
512 
513 		return depthWriteEnable;
514 	}
515 
alphaTestActive()516 	bool Context::alphaTestActive()
517 	{
518 		if(!alphaTestEnable) return false;
519 		if(alphaCompareMode == ALPHA_ALWAYS) return false;
520 		if(alphaReference == 0.0f && alphaCompareMode == ALPHA_GREATEREQUAL) return false;
521 
522 		return true;
523 	}
524 
depthBufferActive()525 	bool Context::depthBufferActive()
526 	{
527 		return depthBuffer && depthBufferEnable;
528 	}
529 
stencilActive()530 	bool Context::stencilActive()
531 	{
532 		return stencilBuffer && stencilEnable;
533 	}
534 
vertexLightingActive()535 	bool Context::vertexLightingActive()
536 	{
537 		if(vertexShader)
538 		{
539 			return false;
540 		}
541 
542 		return lightingEnable && !preTransformed;
543 	}
544 
texCoordActive(int coordinate,int component)545 	bool Context::texCoordActive(int coordinate, int component)
546 	{
547 		bool hasTexture = pointSpriteActive();
548 
549 		if(vertexShader)
550 		{
551 			if(!preTransformed)
552 			{
553 				if(vertexShader->output[T0 + coordinate][component].usage == Shader::USAGE_TEXCOORD)
554 				{
555 					hasTexture = true;
556 				}
557 			}
558 			else
559 			{
560 				hasTexture = true;   // FIXME: Check vertex buffer streams
561 			}
562 		}
563 		else
564 		{
565 			switch(texGen[coordinate])
566 			{
567 			case TEXGEN_NONE:
568 				hasTexture = true;
569 				break;
570 			case TEXGEN_PASSTHRU:
571 				hasTexture = hasTexture || (component < input[TexCoord0 + textureStage[coordinate].texCoordIndex].count);
572 				break;
573 			case TEXGEN_NORMAL:
574 				hasTexture = hasTexture || (component <= 2);
575 				break;
576 			case TEXGEN_POSITION:
577 				hasTexture = hasTexture || (component <= 2);
578 				break;
579 			case TEXGEN_REFLECTION:
580 				hasTexture = hasTexture || (component <= 2);
581 				break;
582 			case TEXGEN_SPHEREMAP:
583 				hasTexture = hasTexture || (component <= 1);
584 				break;
585 			default:
586 				ASSERT(false);
587 			}
588 		}
589 
590 		bool project = isProjectionComponent(coordinate, component);
591 		bool usesTexture = false;
592 
593 		if(pixelShader)
594 		{
595 			usesTexture = pixelShader->usesTexture(coordinate, component) || project;
596 		}
597 		else
598 		{
599 			usesTexture = textureStage[coordinate].usesTexture() || project;
600 		}
601 
602 		return hasTexture && usesTexture;
603 	}
604 
texCoordActive(int coordinate)605 	bool Context::texCoordActive(int coordinate)
606 	{
607 		return texCoordActive(coordinate, 0) ||
608 		       texCoordActive(coordinate, 1) ||
609 		       texCoordActive(coordinate, 2) ||
610 		       texCoordActive(coordinate, 3);
611 	}
612 
isProjectionComponent(unsigned int coordinate,int component)613 	bool Context::isProjectionComponent(unsigned int coordinate, int component)
614 	{
615 		if(pixelShaderVersion() <= 0x0103 && coordinate < 8 && textureTransformProject[coordinate])
616 		{
617 			if(textureTransformCount[coordinate] == 2)
618 			{
619 				if(component == 1) return true;
620 			}
621 			else if(textureTransformCount[coordinate] == 3)
622 			{
623 				if(component == 2) return true;
624 			}
625 			else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0)
626 			{
627 				if(component == 3) return true;
628 			}
629 		}
630 
631 		return false;
632 	}
633 
vertexSpecularActive()634 	bool Context::vertexSpecularActive()
635 	{
636 		return vertexLightingActive() && specularEnable && vertexNormalActive();
637 	}
638 
vertexNormalActive()639 	bool Context::vertexNormalActive()
640 	{
641 		if(vertexShader)
642 		{
643 			return false;
644 		}
645 
646 		return input[Normal];
647 	}
648 
vertexLightActive(int i)649 	bool Context::vertexLightActive(int i)
650 	{
651 		if(vertexShader)
652 		{
653 			return false;
654 		}
655 
656 		return lightingEnable && lightEnable[i];
657 	}
658 
vertexDiffuseMaterialSourceActive()659 	MaterialSource Context::vertexDiffuseMaterialSourceActive()
660 	{
661 		if(vertexShader)
662 		{
663 			return MATERIAL_MATERIAL;
664 		}
665 
666 		if(diffuseMaterialSource == MATERIAL_MATERIAL || !colorVertexEnable ||
667 		   (diffuseMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
668 		   (diffuseMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
669 		{
670 			return MATERIAL_MATERIAL;
671 		}
672 
673 		return diffuseMaterialSource;
674 	}
675 
vertexSpecularMaterialSourceActive()676 	MaterialSource Context::vertexSpecularMaterialSourceActive()
677 	{
678 		if(vertexShader)
679 		{
680 			return MATERIAL_MATERIAL;
681 		}
682 
683 		if(!colorVertexEnable ||
684 		   (specularMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
685 		   (specularMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
686 		{
687 			return MATERIAL_MATERIAL;
688 		}
689 
690 		return specularMaterialSource;
691 	}
692 
vertexAmbientMaterialSourceActive()693 	MaterialSource Context::vertexAmbientMaterialSourceActive()
694 	{
695 		if(vertexShader)
696 		{
697 			return MATERIAL_MATERIAL;
698 		}
699 
700 		if(!colorVertexEnable ||
701 		   (ambientMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
702 		   (ambientMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
703 		{
704 			return MATERIAL_MATERIAL;
705 		}
706 
707 		return ambientMaterialSource;
708 	}
709 
vertexEmissiveMaterialSourceActive()710 	MaterialSource Context::vertexEmissiveMaterialSourceActive()
711 	{
712 		if(vertexShader)
713 		{
714 			return MATERIAL_MATERIAL;
715 		}
716 
717 		if(!colorVertexEnable ||
718 		   (emissiveMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
719 		   (emissiveMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
720 		{
721 			return MATERIAL_MATERIAL;
722 		}
723 
724 		return emissiveMaterialSource;
725 	}
726 
pointSpriteActive()727 	bool Context::pointSpriteActive()
728 	{
729 		return isDrawPoint(true) && pointSpriteEnable;
730 	}
731 
pointScaleActive()732 	bool Context::pointScaleActive()
733 	{
734 		if(vertexShader)
735 		{
736 			return false;
737 		}
738 
739 		return isDrawPoint(true) && pointScaleEnable;
740 	}
741 
alphaBlendActive()742 	bool Context::alphaBlendActive()
743 	{
744 		if(!alphaBlendEnable)
745 		{
746 			return false;
747 		}
748 
749 		if(!colorUsed())
750 		{
751 			return false;
752 		}
753 
754 		bool colorBlend = !(blendOperation() == BLENDOP_SOURCE && sourceBlendFactor() == BLEND_ONE);
755 		bool alphaBlend = separateAlphaBlendEnable ? !(blendOperationAlpha() == BLENDOP_SOURCE && sourceBlendFactorAlpha() == BLEND_ONE) : colorBlend;
756 
757 		return colorBlend || alphaBlend;
758 	}
759 
colorLogicOp()760 	LogicalOperation Context::colorLogicOp()
761 	{
762 		return colorLogicOpEnabled ? logicalOperation : LOGICALOP_COPY;
763 	}
764 
sourceBlendFactor()765 	BlendFactor Context::sourceBlendFactor()
766 	{
767 		if(!alphaBlendEnable) return BLEND_ONE;
768 
769 		switch(blendOperationState)
770 		{
771 		case BLENDOP_ADD:
772 		case BLENDOP_SUB:
773 		case BLENDOP_INVSUB:
774 			return sourceBlendFactorState;
775 		case BLENDOP_MIN:
776 			return BLEND_ONE;
777 		case BLENDOP_MAX:
778 			return BLEND_ONE;
779 		default:
780 			ASSERT(false);
781 		}
782 
783 		return sourceBlendFactorState;
784 	}
785 
destBlendFactor()786 	BlendFactor Context::destBlendFactor()
787 	{
788 		if(!alphaBlendEnable) return BLEND_ZERO;
789 
790 		switch(blendOperationState)
791 		{
792 		case BLENDOP_ADD:
793 		case BLENDOP_SUB:
794 		case BLENDOP_INVSUB:
795 			return destBlendFactorState;
796 		case BLENDOP_MIN:
797 			return BLEND_ONE;
798 		case BLENDOP_MAX:
799 			return BLEND_ONE;
800 		default:
801 			ASSERT(false);
802 		}
803 
804 		return destBlendFactorState;
805 	}
806 
blendOperation()807 	BlendOperation Context::blendOperation()
808 	{
809 		if(!alphaBlendEnable) return BLENDOP_SOURCE;
810 
811 		switch(blendOperationState)
812 		{
813 		case BLENDOP_ADD:
814 			if(sourceBlendFactor() == BLEND_ZERO)
815 			{
816 				if(destBlendFactor() == BLEND_ZERO)
817 				{
818 					return BLENDOP_NULL;
819 				}
820 				else
821 				{
822 					return BLENDOP_DEST;
823 				}
824 			}
825 			else if(sourceBlendFactor() == BLEND_ONE)
826 			{
827 				if(destBlendFactor() == BLEND_ZERO)
828 				{
829 					return BLENDOP_SOURCE;
830 				}
831 				else
832 				{
833 					return BLENDOP_ADD;
834 				}
835 			}
836 			else
837 			{
838 				if(destBlendFactor() == BLEND_ZERO)
839 				{
840 					return BLENDOP_SOURCE;
841 				}
842 				else
843 				{
844 					return BLENDOP_ADD;
845 				}
846 			}
847 		case BLENDOP_SUB:
848 			if(sourceBlendFactor() == BLEND_ZERO)
849 			{
850 				return BLENDOP_NULL;   // Negative, clamped to zero
851 			}
852 			else if(sourceBlendFactor() == BLEND_ONE)
853 			{
854 				if(destBlendFactor() == BLEND_ZERO)
855 				{
856 					return BLENDOP_SOURCE;
857 				}
858 				else
859 				{
860 					return BLENDOP_SUB;
861 				}
862 			}
863 			else
864 			{
865 				if(destBlendFactor() == BLEND_ZERO)
866 				{
867 					return BLENDOP_SOURCE;
868 				}
869 				else
870 				{
871 					return BLENDOP_SUB;
872 				}
873 			}
874 		case BLENDOP_INVSUB:
875 			if(sourceBlendFactor() == BLEND_ZERO)
876 			{
877 				if(destBlendFactor() == BLEND_ZERO)
878 				{
879 					return BLENDOP_NULL;
880 				}
881 				else
882 				{
883 					return BLENDOP_DEST;
884 				}
885 			}
886 			else if(sourceBlendFactor() == BLEND_ONE)
887 			{
888 				if(destBlendFactor() == BLEND_ZERO)
889 				{
890 					return BLENDOP_NULL;   // Negative, clamped to zero
891 				}
892 				else
893 				{
894 					return BLENDOP_INVSUB;
895 				}
896 			}
897 			else
898 			{
899 				if(destBlendFactor() == BLEND_ZERO)
900 				{
901 					return BLENDOP_NULL;   // Negative, clamped to zero
902 				}
903 				else
904 				{
905 					return BLENDOP_INVSUB;
906 				}
907 			}
908 		case BLENDOP_MIN:
909 			return BLENDOP_MIN;
910 		case BLENDOP_MAX:
911 			return BLENDOP_MAX;
912 		default:
913 			ASSERT(false);
914 		}
915 
916 		return blendOperationState;
917 	}
918 
sourceBlendFactorAlpha()919 	BlendFactor Context::sourceBlendFactorAlpha()
920 	{
921 		if(!separateAlphaBlendEnable)
922 		{
923 			return sourceBlendFactor();
924 		}
925 		else
926 		{
927 			switch(blendOperationStateAlpha)
928 			{
929 			case BLENDOP_ADD:
930 			case BLENDOP_SUB:
931 			case BLENDOP_INVSUB:
932 				return sourceBlendFactorStateAlpha;
933 			case BLENDOP_MIN:
934 				return BLEND_ONE;
935 			case BLENDOP_MAX:
936 				return BLEND_ONE;
937 			default:
938 				ASSERT(false);
939 			}
940 
941 			return sourceBlendFactorStateAlpha;
942 		}
943 	}
944 
destBlendFactorAlpha()945 	BlendFactor Context::destBlendFactorAlpha()
946 	{
947 		if(!separateAlphaBlendEnable)
948 		{
949 			return destBlendFactor();
950 		}
951 		else
952 		{
953 			switch(blendOperationStateAlpha)
954 			{
955 			case BLENDOP_ADD:
956 			case BLENDOP_SUB:
957 			case BLENDOP_INVSUB:
958 				return destBlendFactorStateAlpha;
959 			case BLENDOP_MIN:
960 				return BLEND_ONE;
961 			case BLENDOP_MAX:
962 				return BLEND_ONE;
963 			default:
964 				ASSERT(false);
965 			}
966 
967 			return destBlendFactorStateAlpha;
968 		}
969 	}
970 
blendOperationAlpha()971 	BlendOperation Context::blendOperationAlpha()
972 	{
973 		if(!separateAlphaBlendEnable)
974 		{
975 			return blendOperation();
976 		}
977 		else
978 		{
979 			switch(blendOperationStateAlpha)
980 			{
981 			case BLENDOP_ADD:
982 				if(sourceBlendFactorAlpha() == BLEND_ZERO)
983 				{
984 					if(destBlendFactorAlpha() == BLEND_ZERO)
985 					{
986 						return BLENDOP_NULL;
987 					}
988 					else
989 					{
990 						return BLENDOP_DEST;
991 					}
992 				}
993 				else if(sourceBlendFactorAlpha() == BLEND_ONE)
994 				{
995 					if(destBlendFactorAlpha() == BLEND_ZERO)
996 					{
997 						return BLENDOP_SOURCE;
998 					}
999 					else
1000 					{
1001 						return BLENDOP_ADD;
1002 					}
1003 				}
1004 				else
1005 				{
1006 					if(destBlendFactorAlpha() == BLEND_ZERO)
1007 					{
1008 						return BLENDOP_SOURCE;
1009 					}
1010 					else
1011 					{
1012 						return BLENDOP_ADD;
1013 					}
1014 				}
1015 			case BLENDOP_SUB:
1016 				if(sourceBlendFactorAlpha() == BLEND_ZERO)
1017 				{
1018 					return BLENDOP_NULL;   // Negative, clamped to zero
1019 				}
1020 				else if(sourceBlendFactorAlpha() == BLEND_ONE)
1021 				{
1022 					if(destBlendFactorAlpha() == BLEND_ZERO)
1023 					{
1024 						return BLENDOP_SOURCE;
1025 					}
1026 					else
1027 					{
1028 						return BLENDOP_SUB;
1029 					}
1030 				}
1031 				else
1032 				{
1033 					if(destBlendFactorAlpha() == BLEND_ZERO)
1034 					{
1035 						return BLENDOP_SOURCE;
1036 					}
1037 					else
1038 					{
1039 						return BLENDOP_SUB;
1040 					}
1041 				}
1042 			case BLENDOP_INVSUB:
1043 				if(sourceBlendFactorAlpha() == BLEND_ZERO)
1044 				{
1045 					if(destBlendFactorAlpha() == BLEND_ZERO)
1046 					{
1047 						return BLENDOP_NULL;
1048 					}
1049 					else
1050 					{
1051 						return BLENDOP_DEST;
1052 					}
1053 				}
1054 				else if(sourceBlendFactorAlpha() == BLEND_ONE)
1055 				{
1056 					if(destBlendFactorAlpha() == BLEND_ZERO)
1057 					{
1058 						return BLENDOP_NULL;   // Negative, clamped to zero
1059 					}
1060 					else
1061 					{
1062 						return BLENDOP_INVSUB;
1063 					}
1064 				}
1065 				else
1066 				{
1067 					if(destBlendFactorAlpha() == BLEND_ZERO)
1068 					{
1069 						return BLENDOP_NULL;   // Negative, clamped to zero
1070 					}
1071 					else
1072 					{
1073 						return BLENDOP_INVSUB;
1074 					}
1075 				}
1076 			case BLENDOP_MIN:
1077 				return BLENDOP_MIN;
1078 			case BLENDOP_MAX:
1079 				return BLENDOP_MAX;
1080 			default:
1081 				ASSERT(false);
1082 			}
1083 
1084 			return blendOperationStateAlpha;
1085 		}
1086 	}
1087 
indexedVertexBlendActive()1088 	bool Context::indexedVertexBlendActive()
1089 	{
1090 		if(vertexShader)
1091 		{
1092 			return false;
1093 		}
1094 
1095 		return indexedVertexBlendEnable;
1096 	}
1097 
vertexBlendMatrixCountActive()1098 	int Context::vertexBlendMatrixCountActive()
1099 	{
1100 		if(vertexShader)
1101 		{
1102 			return 0;
1103 		}
1104 
1105 		return vertexBlendMatrixCount;
1106 	}
1107 
localViewerActive()1108 	bool Context::localViewerActive()
1109 	{
1110 		if(vertexShader)
1111 		{
1112 			return false;
1113 		}
1114 
1115 		return localViewer;
1116 	}
1117 
normalizeNormalsActive()1118 	bool Context::normalizeNormalsActive()
1119 	{
1120 		if(vertexShader)
1121 		{
1122 			return false;
1123 		}
1124 
1125 		return normalizeNormals;
1126 	}
1127 
vertexFogModeActive()1128 	FogMode Context::vertexFogModeActive()
1129 	{
1130 		if(vertexShader || !fogActive())
1131 		{
1132 			return FOG_NONE;
1133 		}
1134 
1135 		return vertexFogMode;
1136 	}
1137 
rangeFogActive()1138 	bool Context::rangeFogActive()
1139 	{
1140 		if(vertexShader || !fogActive())
1141 		{
1142 			return false;
1143 		}
1144 
1145 		return rangeFogEnable;
1146 	}
1147 
texGenActive(int stage)1148 	TexGen Context::texGenActive(int stage)
1149 	{
1150 		if(vertexShader || !texCoordActive(stage))
1151 		{
1152 			return TEXGEN_PASSTHRU;
1153 		}
1154 
1155 		return texGen[stage];
1156 	}
1157 
textureTransformCountActive(int stage)1158 	int Context::textureTransformCountActive(int stage)
1159 	{
1160 		if(vertexShader || !texCoordActive(stage))
1161 		{
1162 			return 0;
1163 		}
1164 
1165 		return textureTransformCount[stage];
1166 	}
1167 
texCoordIndexActive(int stage)1168 	int Context::texCoordIndexActive(int stage)
1169 	{
1170 		if(vertexShader || !texCoordActive(stage))
1171 		{
1172 			return stage;
1173 		}
1174 
1175 		return textureStage[stage].texCoordIndex;
1176 	}
1177 
perspectiveActive()1178 	bool Context::perspectiveActive()
1179 	{
1180 		if(!colorUsed())
1181 		{
1182 			return false;
1183 		}
1184 
1185 		if(!perspectiveCorrection)
1186 		{
1187 			return false;
1188 		}
1189 
1190 		if(isDrawPoint(true))
1191 		{
1192 			return false;
1193 		}
1194 
1195 		return true;
1196 	}
1197 
diffuseUsed()1198 	bool Context::diffuseUsed()
1199 	{
1200 		return diffuseUsed(0) || diffuseUsed(1) || diffuseUsed(2) || diffuseUsed(3);
1201 	}
1202 
diffuseUsed(int component)1203 	bool Context::diffuseUsed(int component)
1204 	{
1205 		if(!colorUsed())
1206 		{
1207 			return false;
1208 		}
1209 
1210 		if(pixelShader)
1211 		{
1212 			return pixelShader->usesDiffuse(component);
1213 		}
1214 
1215 		// Directly using the diffuse input color
1216 		for(int i = 0; i < 8; i++)
1217 		{
1218 			if(textureStage[i].isStageDisabled())
1219 			{
1220 				break;
1221 			}
1222 
1223 			if(textureStage[i].usesDiffuse())
1224 			{
1225 				return true;
1226 			}
1227 		}
1228 
1229 		// Using the current color (initialized to diffuse) before it's overwritten
1230 		for(int i = 0; i < 8; i++)
1231 		{
1232 			if(textureStage[i].usesCurrent() || textureStage[i].isStageDisabled())   // Current color contains diffuse before being overwritten
1233 			{
1234 				return true;
1235 			}
1236 
1237 			if(textureStage[i].writesCurrent())
1238 			{
1239 				return false;
1240 			}
1241 		}
1242 
1243 		return true;
1244 	}
1245 
diffuseActive()1246 	bool Context::diffuseActive()
1247 	{
1248 		return diffuseActive(0) || diffuseActive(1) || diffuseActive(2) || diffuseActive(3);
1249 	}
1250 
diffuseActive(int component)1251 	bool Context::diffuseActive(int component)
1252 	{
1253 		if(!colorUsed())
1254 		{
1255 			return false;
1256 		}
1257 
1258 		// Vertex processor provides diffuse component
1259 		bool vertexDiffuse;
1260 
1261 		if(vertexShader)
1262 		{
1263 			vertexDiffuse = vertexShader->output[C0][component].active();
1264 		}
1265 		else if(!preTransformed)
1266 		{
1267 			vertexDiffuse = input[Color0] || lightingEnable;
1268 		}
1269 		else
1270 		{
1271 			vertexDiffuse = input[Color0];
1272 		}
1273 
1274 		// Pixel processor requires diffuse component
1275 		bool pixelDiffuse = diffuseUsed(component);
1276 
1277 		return vertexDiffuse && pixelDiffuse;
1278 	}
1279 
specularUsed()1280 	bool Context::specularUsed()
1281 	{
1282 		return Context::specularUsed(0) || Context::specularUsed(1) || Context::specularUsed(2) || Context::specularUsed(3);
1283 	}
1284 
specularUsed(int component)1285 	bool Context::specularUsed(int component)
1286 	{
1287 		if(!colorUsed())
1288 		{
1289 			return false;
1290 		}
1291 
1292 		if(pixelShader)
1293 		{
1294 			return pixelShader->usesSpecular(component);
1295 		}
1296 
1297 		bool pixelSpecular = specularEnable;
1298 
1299 		for(int i = 0; i < 8; i++)
1300 		{
1301 			if(textureStage[i].isStageDisabled()) break;
1302 
1303 			pixelSpecular = pixelSpecular || textureStage[i].usesSpecular();
1304 		}
1305 
1306 		return pixelSpecular;
1307 	}
1308 
specularActive()1309 	bool Context::specularActive()
1310 	{
1311 		return specularActive(0) || specularActive(1) || specularActive(2) || specularActive(3);
1312 	}
1313 
specularActive(int component)1314 	bool Context::specularActive(int component)
1315 	{
1316 		if(!colorUsed())
1317 		{
1318 			return false;
1319 		}
1320 
1321 		// Vertex processor provides specular component
1322 		bool vertexSpecular;
1323 
1324 		if(!vertexShader)
1325 		{
1326 			vertexSpecular = input[Color1] || (lightingEnable && specularEnable);
1327 		}
1328 		else
1329 		{
1330 			vertexSpecular = vertexShader->output[C1][component].active();
1331 		}
1332 
1333 		// Pixel processor requires specular component
1334 		bool pixelSpecular = specularUsed(component);
1335 
1336 		return vertexSpecular && pixelSpecular;
1337 	}
1338 
colorActive(int color,int component)1339 	bool Context::colorActive(int color, int component)
1340 	{
1341 		if(color == 0)
1342 		{
1343 			return diffuseActive(component);
1344 		}
1345 		else
1346 		{
1347 			return specularActive(component);
1348 		}
1349 	}
1350 
textureActive()1351 	bool Context::textureActive()
1352 	{
1353 		for(int i = 0; i < 8; i++)
1354 		{
1355 			if(textureActive(i))
1356 			{
1357 				return true;
1358 			}
1359 		}
1360 
1361 		return false;
1362 	}
1363 
textureActive(int coordinate)1364 	bool Context::textureActive(int coordinate)
1365 	{
1366 		return textureActive(coordinate, 0) || textureActive(coordinate, 1) || textureActive(coordinate, 2) || textureActive(coordinate, 3);
1367 	}
1368 
textureActive(int coordinate,int component)1369 	bool Context::textureActive(int coordinate, int component)
1370 	{
1371 		if(!colorUsed())
1372 		{
1373 			return false;
1374 		}
1375 
1376 		if(!texCoordActive(coordinate, component))
1377 		{
1378 			return false;
1379 		}
1380 
1381 		if(textureTransformProject[coordinate] && pixelShaderVersion() <= 0x0103)
1382 		{
1383 			if(textureTransformCount[coordinate] == 2)
1384 			{
1385 				if(component == 1) return true;
1386 			}
1387 			else if(textureTransformCount[coordinate] == 3)
1388 			{
1389 				if(component == 2) return true;
1390 			}
1391 			else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0)
1392 			{
1393 				if(component == 3) return true;
1394 			}
1395 		}
1396 
1397 		if(!pixelShader)
1398 		{
1399 			bool texture = textureStage[coordinate].usesTexture();
1400 			bool cube = sampler[coordinate].hasCubeTexture();
1401 			bool volume = sampler[coordinate].hasVolumeTexture();
1402 
1403 			if(texture)
1404 			{
1405 				for(int i = coordinate; i >= 0; i--)
1406 				{
1407 					if(textureStage[i].stageOperation == TextureStage::STAGE_DISABLE)
1408 					{
1409 						return false;
1410 					}
1411 				}
1412 			}
1413 
1414 			switch(component)
1415 			{
1416 			case 0:
1417 				return texture;
1418 			case 1:
1419 				return texture;
1420 			case 2:
1421 				return (texture && (cube || volume));
1422 			case 3:
1423 				return false;
1424 			}
1425 		}
1426 		else
1427 		{
1428 			return pixelShader->usesTexture(coordinate, component);
1429 		}
1430 
1431 		return false;
1432 	}
1433 
pixelShaderVersion() const1434 	unsigned short Context::pixelShaderVersion() const
1435 	{
1436 		return pixelShader ? pixelShader->getVersion() : 0x0000;
1437 	}
1438 
vertexShaderVersion() const1439 	unsigned short Context::vertexShaderVersion() const
1440 	{
1441 		return vertexShader ? vertexShader->getVersion() : 0x0000;
1442 	}
1443 
getMultiSampleCount() const1444 	int Context::getMultiSampleCount() const
1445 	{
1446 		return renderTarget[0] ? renderTarget[0]->getMultiSampleCount() : 1;
1447 	}
1448 
getSuperSampleCount() const1449 	int Context::getSuperSampleCount() const
1450 	{
1451 		return renderTarget[0] ? renderTarget[0]->getSuperSampleCount() : 1;
1452 	}
1453 
renderTargetInternalFormat(int index)1454 	Format Context::renderTargetInternalFormat(int index)
1455 	{
1456 		if(renderTarget[index])
1457 		{
1458 			return renderTarget[index]->getInternalFormat();
1459 		}
1460 		else
1461 		{
1462 			return FORMAT_NULL;
1463 		}
1464 	}
1465 
colorWriteActive()1466 	int Context::colorWriteActive()
1467 	{
1468 		return colorWriteActive(0) | colorWriteActive(1) | colorWriteActive(2) | colorWriteActive(3);
1469 	}
1470 
colorWriteActive(int index)1471 	int Context::colorWriteActive(int index)
1472 	{
1473 		if(!renderTarget[index] || renderTarget[index]->getInternalFormat() == FORMAT_NULL)
1474 		{
1475 			return 0;
1476 		}
1477 
1478 		if(blendOperation() == BLENDOP_DEST && destBlendFactor() == BLEND_ONE &&
1479 		   (!separateAlphaBlendEnable || (blendOperationAlpha() == BLENDOP_DEST && destBlendFactorAlpha() == BLEND_ONE)))
1480 		{
1481 			return 0;
1482 		}
1483 
1484 		return colorWriteMask[index];
1485 	}
1486 
colorUsed()1487 	bool Context::colorUsed()
1488 	{
1489 		return colorWriteActive() || alphaTestActive() || (pixelShader && pixelShader->containsKill());
1490 	}
1491 }
1492