blob: 03274781952f1a4fea7384c12478b562e3cbccc8 [file] [log] [blame]
// 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 <string.h>
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<float> &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;
}
}