// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "TextureStage.hpp" #include "Sampler.hpp" #include "Common/Debug.hpp" #include namespace sw { TextureStage::State::State() { memset(this, 0, sizeof(State)); } TextureStage::TextureStage() : sampler(0), previousStage(0) { } TextureStage::~TextureStage() { } void TextureStage::init(int stage, const Sampler *sampler, const TextureStage *previousStage) { this->stage = stage; stageOperation = (stage == 0 ? STAGE_MODULATE : STAGE_DISABLE); firstArgument = SOURCE_TEXTURE; secondArgument = SOURCE_CURRENT; thirdArgument = SOURCE_CURRENT; stageOperationAlpha = (stage == 0 ? STAGE_SELECTARG1 : STAGE_DISABLE); firstArgumentAlpha = SOURCE_DIFFUSE; secondArgumentAlpha = SOURCE_CURRENT; thirdArgumentAlpha = SOURCE_CURRENT; firstModifier = MODIFIER_COLOR; secondModifier = MODIFIER_COLOR; thirdModifier = MODIFIER_COLOR; firstModifierAlpha = MODIFIER_COLOR; secondModifierAlpha = MODIFIER_COLOR; thirdModifierAlpha = MODIFIER_COLOR; destinationArgument = DESTINATION_CURRENT; texCoordIndex = stage; this->sampler = sampler; this->previousStage = previousStage; } TextureStage::State TextureStage::textureStageState() const { State state; if(!isStageDisabled()) { state.stageOperation = stageOperation; state.firstArgument = firstArgument; state.secondArgument = secondArgument; state.thirdArgument = thirdArgument; state.stageOperationAlpha = stageOperationAlpha; state.firstArgumentAlpha = firstArgumentAlpha; state.secondArgumentAlpha = secondArgumentAlpha; state.thirdArgumentAlpha = thirdArgumentAlpha; state.firstModifier = firstModifier; state.secondModifier = secondModifier; state.thirdModifier = thirdModifier; state.firstModifierAlpha = firstModifierAlpha; state.secondModifierAlpha = secondModifierAlpha; state.thirdModifierAlpha = thirdModifierAlpha; state.destinationArgument = destinationArgument; state.texCoordIndex = texCoordIndex; state.cantUnderflow = sampler->hasUnsignedTexture() || !usesTexture(); state.usesTexture = usesTexture(); } return state; } void TextureStage::setConstantColor(const Color &constantColor) { // FIXME: Compact into generic function // FIXME: Clamp short r = iround(4095 * constantColor.r); short g = iround(4095 * constantColor.g); short b = iround(4095 * constantColor.b); short a = iround(4095 * constantColor.a); uniforms.constantColor4[0][0] = uniforms.constantColor4[0][1] = uniforms.constantColor4[0][2] = uniforms.constantColor4[0][3] = r; uniforms.constantColor4[1][0] = uniforms.constantColor4[1][1] = uniforms.constantColor4[1][2] = uniforms.constantColor4[1][3] = g; uniforms.constantColor4[2][0] = uniforms.constantColor4[2][1] = uniforms.constantColor4[2][2] = uniforms.constantColor4[2][3] = b; uniforms.constantColor4[3][0] = uniforms.constantColor4[3][1] = uniforms.constantColor4[3][2] = uniforms.constantColor4[3][3] = a; } void TextureStage::setBumpmapMatrix(int element, float value) { uniforms.bumpmapMatrix4F[element / 2][element % 2][0] = value; uniforms.bumpmapMatrix4F[element / 2][element % 2][1] = value; uniforms.bumpmapMatrix4F[element / 2][element % 2][2] = value; uniforms.bumpmapMatrix4F[element / 2][element % 2][3] = value; uniforms.bumpmapMatrix4W[element / 2][element % 2][0] = iround(4095 * value); uniforms.bumpmapMatrix4W[element / 2][element % 2][1] = iround(4095 * value); uniforms.bumpmapMatrix4W[element / 2][element % 2][2] = iround(4095 * value); uniforms.bumpmapMatrix4W[element / 2][element % 2][3] = iround(4095 * value); } void TextureStage::setLuminanceScale(float value) { short scale = iround(4095 * value); uniforms.luminanceScale4[0] = uniforms.luminanceScale4[1] = uniforms.luminanceScale4[2] = uniforms.luminanceScale4[3] = scale; } void TextureStage::setLuminanceOffset(float value) { short offset = iround(4095 * value); uniforms.luminanceOffset4[0] = uniforms.luminanceOffset4[1] = uniforms.luminanceOffset4[2] = uniforms.luminanceOffset4[3] = offset; } void TextureStage::setTexCoordIndex(unsigned int texCoordIndex) { ASSERT(texCoordIndex < 8); this->texCoordIndex = texCoordIndex; } void TextureStage::setStageOperation(StageOperation stageOperation) { this->stageOperation = stageOperation; } void TextureStage::setFirstArgument(SourceArgument firstArgument) { this->firstArgument = firstArgument; } void TextureStage::setSecondArgument(SourceArgument secondArgument) { this->secondArgument = secondArgument; } void TextureStage::setThirdArgument(SourceArgument thirdArgument) { this->thirdArgument = thirdArgument; } void TextureStage::setStageOperationAlpha(StageOperation stageOperationAlpha) { this->stageOperationAlpha = stageOperationAlpha; } void TextureStage::setFirstArgumentAlpha(SourceArgument firstArgumentAlpha) { this->firstArgumentAlpha = firstArgumentAlpha; } void TextureStage::setSecondArgumentAlpha(SourceArgument secondArgumentAlpha) { this->secondArgumentAlpha = secondArgumentAlpha; } void TextureStage::setThirdArgumentAlpha(SourceArgument thirdArgumentAlpha) { this->thirdArgumentAlpha= thirdArgumentAlpha; } void TextureStage::setFirstModifier(ArgumentModifier firstModifier) { this->firstModifier = firstModifier; } void TextureStage::setSecondModifier(ArgumentModifier secondModifier) { this->secondModifier = secondModifier; } void TextureStage::setThirdModifier(ArgumentModifier thirdModifier) { this->thirdModifier = thirdModifier; } void TextureStage::setFirstModifierAlpha(ArgumentModifier firstModifierAlpha) { this->firstModifierAlpha = firstModifierAlpha; } void TextureStage::setSecondModifierAlpha(ArgumentModifier secondModifierAlpha) { this->secondModifierAlpha = secondModifierAlpha; } void TextureStage::setThirdModifierAlpha(ArgumentModifier thirdModifierAlpha) { this->thirdModifierAlpha = thirdModifierAlpha; } void TextureStage::setDestinationArgument(DestinationArgument destinationArgument) { this->destinationArgument = destinationArgument; } bool TextureStage::usesColor(SourceArgument source) const { // One argument if(stageOperation == STAGE_SELECTARG1 || stageOperation == STAGE_PREMODULATE) { return firstArgument == source; } else if(stageOperation == STAGE_SELECTARG2) { return secondArgument == source; } else if(stageOperation == STAGE_SELECTARG3) { return thirdArgument == source; } else { // Two arguments or more if(firstArgument == source || secondArgument == source) { return true; } // Three arguments if(stageOperation == STAGE_MULTIPLYADD || stageOperation == STAGE_LERP) { return thirdArgument == source; } } return false; } bool TextureStage::usesAlpha(SourceArgument source) const { if(stageOperationAlpha == STAGE_DISABLE) { return false; } if(source == SOURCE_TEXTURE) { if(stageOperation == STAGE_BLENDTEXTUREALPHA || stageOperation == STAGE_BLENDTEXTUREALPHAPM) { return true; } } else if(source == SOURCE_CURRENT) { if(stageOperation == STAGE_BLENDCURRENTALPHA) { return true; } } else if(source == SOURCE_DIFFUSE) { if(stageOperation == STAGE_BLENDDIFFUSEALPHA) { return true; } } else if(source == SOURCE_TFACTOR) { if(stageOperation == STAGE_BLENDFACTORALPHA) { return true; } } // One argument if(stageOperation == STAGE_SELECTARG1 || stageOperation == STAGE_PREMODULATE) { if(firstArgument == source && (firstModifier == MODIFIER_ALPHA || firstModifier == MODIFIER_INVALPHA)) { return true; } } else if(stageOperation == STAGE_SELECTARG2) { if(secondArgument == source && (secondModifier == MODIFIER_ALPHA || secondModifier == MODIFIER_INVALPHA)) { return true; } } else if(stageOperation == STAGE_SELECTARG3) { if(thirdArgument == source && (thirdModifier == MODIFIER_ALPHA || thirdModifier == MODIFIER_INVALPHA)) { return true; } } else { // Two arguments or more if(firstArgument == source || secondArgument == source) { if(firstArgument == source && (firstModifier == MODIFIER_ALPHA || firstModifier == MODIFIER_INVALPHA)) { return true; } if(secondArgument == source && (secondModifier == MODIFIER_ALPHA || secondModifier == MODIFIER_INVALPHA)) { return true; } } // Three arguments if(stageOperation == STAGE_MULTIPLYADD || stageOperation == STAGE_LERP) { if(thirdArgument == source && (thirdModifier == MODIFIER_ALPHA || thirdModifier == MODIFIER_INVALPHA)) { return true; } } } // One argument if(stageOperationAlpha == STAGE_SELECTARG1 || stageOperationAlpha == STAGE_PREMODULATE) { return firstArgumentAlpha == source; } else if(stageOperationAlpha == STAGE_SELECTARG2) { return secondArgumentAlpha == source; } else if(stageOperationAlpha == STAGE_SELECTARG3) { return thirdArgumentAlpha == source; } else { // Two arguments or more if(firstArgumentAlpha == source || secondArgumentAlpha == source) { return true; } // Three arguments if(stageOperationAlpha == STAGE_MULTIPLYADD || stageOperationAlpha == STAGE_LERP) { return thirdArgumentAlpha == source; } } return false; } bool TextureStage::uses(SourceArgument source) const { return usesColor(source) || usesAlpha(source); } bool TextureStage::usesCurrent() const { return uses(SOURCE_CURRENT) || (stageOperation == STAGE_BLENDCURRENTALPHA || stageOperationAlpha == STAGE_BLENDCURRENTALPHA); } bool TextureStage::usesDiffuse() const { return uses(SOURCE_DIFFUSE) || (stageOperation == STAGE_BLENDDIFFUSEALPHA || stageOperationAlpha == STAGE_BLENDDIFFUSEALPHA); } bool TextureStage::usesSpecular() const { return uses(SOURCE_SPECULAR); } bool TextureStage::usesTexture() const { return uses(SOURCE_TEXTURE) || stageOperation == STAGE_BLENDTEXTUREALPHA || stageOperationAlpha == STAGE_BLENDTEXTUREALPHA || stageOperation == STAGE_BLENDTEXTUREALPHAPM || stageOperationAlpha == STAGE_BLENDTEXTUREALPHAPM || (previousStage && previousStage->stageOperation == STAGE_PREMODULATE) || (previousStage && previousStage->stageOperationAlpha == STAGE_PREMODULATE); } bool TextureStage::isStageDisabled() const { bool disabled = (stageOperation == STAGE_DISABLE) || (!sampler->hasTexture() && usesTexture()); if(!previousStage || disabled) { return disabled; } else { return previousStage->isStageDisabled(); } } bool TextureStage::writesCurrent() const { return !isStageDisabled() && destinationArgument == DESTINATION_CURRENT && stageOperation != STAGE_BUMPENVMAP && stageOperation != STAGE_BUMPENVMAPLUMINANCE; } }