blob: 4e7395ef0b7d23d4c27a8c683033fbb8c7e7afff [file] [log] [blame]
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GLES1Renderer.cpp: Implements the GLES1Renderer renderer.
#include "libANGLE/GLES1Renderer.h"
#include <string.h>
#include <iterator>
#include <sstream>
#include <vector>
#include "libANGLE/Context.h"
#include "libANGLE/Context.inl.h"
#include "libANGLE/Program.h"
#include "libANGLE/ResourceManager.h"
#include "libANGLE/Shader.h"
#include "libANGLE/State.h"
#include "libANGLE/renderer/ContextImpl.h"
namespace
{
#include "libANGLE/GLES1Shaders.inc"
} // anonymous namespace
namespace gl
{
GLES1Renderer::GLES1Renderer() : mRendererProgramInitialized(false) {}
void GLES1Renderer::onDestroy(Context *context, State *state)
{
if (mRendererProgramInitialized)
{
(void)state->setProgram(context, 0);
mShaderPrograms->deleteProgram(context, mProgramState.program);
mShaderPrograms->release(context);
mShaderPrograms = nullptr;
mRendererProgramInitialized = false;
}
}
GLES1Renderer::~GLES1Renderer() = default;
angle::Result GLES1Renderer::prepareForDraw(PrimitiveMode mode, Context *context, State *glState)
{
ANGLE_TRY(initializeRendererProgram(context, glState));
GLES1State &gles1State = glState->gles1();
Program *programObject = getProgram(mProgramState.program);
GLES1UniformBuffers &uniformBuffers = mUniformBuffers;
// If anything is dirty in gles1 or the common parts of gles1/2, just redo these parts
// completely for now.
// Feature enables
{
setUniform1i(context, programObject, mProgramState.enableAlphaTestLoc,
glState->getEnableFeature(GL_ALPHA_TEST));
setUniform1i(context, programObject, mProgramState.enableLightingLoc,
glState->getEnableFeature(GL_LIGHTING));
setUniform1i(context, programObject, mProgramState.enableRescaleNormalLoc,
glState->getEnableFeature(GL_RESCALE_NORMAL));
setUniform1i(context, programObject, mProgramState.enableNormalizeLoc,
glState->getEnableFeature(GL_NORMALIZE));
setUniform1i(context, programObject, mProgramState.enableColorMaterialLoc,
glState->getEnableFeature(GL_COLOR_MATERIAL));
setUniform1i(context, programObject, mProgramState.fogEnableLoc,
glState->getEnableFeature(GL_FOG));
bool enableClipPlanes = false;
for (int i = 0; i < kClipPlaneCount; i++)
{
uniformBuffers.clipPlaneEnables[i] = glState->getEnableFeature(GL_CLIP_PLANE0 + i);
enableClipPlanes = enableClipPlanes || uniformBuffers.clipPlaneEnables[i];
}
setUniform1i(context, programObject, mProgramState.enableClipPlanesLoc, enableClipPlanes);
}
// Texture unit enables and format info
{
std::array<GLint, kTexUnitCount> &tex2DEnables = uniformBuffers.tex2DEnables;
std::array<GLint, kTexUnitCount> &texCubeEnables = uniformBuffers.texCubeEnables;
std::vector<int> tex2DFormats = {GL_RGBA, GL_RGBA, GL_RGBA, GL_RGBA};
Vec4Uniform *cropRectBuffer = uniformBuffers.texCropRects.data();
for (int i = 0; i < kTexUnitCount; i++)
{
// GL_OES_cube_map allows only one of TEXTURE_2D / TEXTURE_CUBE_MAP
// to be enabled per unit, thankfully. From the extension text:
//
// -- Section 3.8.10 "Texture Application"
//
// Replace the beginning sentences of the first paragraph (page 138)
// with:
//
// "Texturing is enabled or disabled using the generic Enable
// and Disable commands, respectively, with the symbolic constants
// TEXTURE_2D or TEXTURE_CUBE_MAP_OES to enable the two-dimensional or cube
// map texturing respectively. If the cube map texture and the two-
// dimensional texture are enabled, then cube map texturing is used. If
// texturing is disabled, a rasterized fragment is passed on unaltered to the
// next stage of the GL (although its texture coordinates may be discarded).
// Otherwise, a texture value is found according to the parameter values of
// the currently bound texture image of the appropriate dimensionality.
texCubeEnables[i] = gles1State.isTextureTargetEnabled(i, TextureType::CubeMap);
tex2DEnables[i] =
!texCubeEnables[i] && (gles1State.isTextureTargetEnabled(i, TextureType::_2D));
Texture *curr2DTexture = glState->getSamplerTexture(i, TextureType::_2D);
if (curr2DTexture)
{
tex2DFormats[i] = gl::GetUnsizedFormat(
curr2DTexture->getFormat(TextureTarget::_2D, 0).info->internalFormat);
const gl::Rectangle &cropRect = curr2DTexture->getCrop();
GLfloat textureWidth =
static_cast<GLfloat>(curr2DTexture->getWidth(TextureTarget::_2D, 0));
GLfloat textureHeight =
static_cast<GLfloat>(curr2DTexture->getHeight(TextureTarget::_2D, 0));
if (textureWidth > 0.0f && textureHeight > 0.0f)
{
cropRectBuffer[i][0] = cropRect.x / textureWidth;
cropRectBuffer[i][1] = cropRect.y / textureHeight;
cropRectBuffer[i][2] = cropRect.width / textureWidth;
cropRectBuffer[i][3] = cropRect.height / textureHeight;
}
}
}
setUniform1iv(context, programObject, mProgramState.enableTexture2DLoc, kTexUnitCount,
tex2DEnables.data());
setUniform1iv(context, programObject, mProgramState.enableTextureCubeMapLoc, kTexUnitCount,
texCubeEnables.data());
setUniform1iv(context, programObject, mProgramState.textureFormatLoc, kTexUnitCount,
tex2DFormats.data());
setUniform4fv(programObject, mProgramState.drawTextureNormalizedCropRectLoc, kTexUnitCount,
reinterpret_cast<GLfloat *>(cropRectBuffer));
}
// Client state / current vector enables
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_CLIENT_STATE_ENABLE) ||
gles1State.isDirty(GLES1State::DIRTY_GLES1_CURRENT_VECTOR))
{
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::Normal))
{
const angle::Vector3 normal = gles1State.getCurrentNormal();
context->vertexAttrib3f(kNormalAttribIndex, normal.x(), normal.y(), normal.z());
}
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::Color))
{
const ColorF color = gles1State.getCurrentColor();
context->vertexAttrib4f(kColorAttribIndex, color.red, color.green, color.blue,
color.alpha);
}
if (!gles1State.isClientStateEnabled(ClientVertexArrayType::PointSize))
{
GLfloat pointSize = gles1State.mPointParameters.pointSize;
context->vertexAttrib1f(kPointSizeAttribIndex, pointSize);
}
for (int i = 0; i < kTexUnitCount; i++)
{
if (!gles1State.mTexCoordArrayEnabled[i])
{
const TextureCoordF texcoord = gles1State.getCurrentTextureCoords(i);
context->vertexAttrib4f(kTextureCoordAttribIndexBase + i, texcoord.s, texcoord.t,
texcoord.r, texcoord.q);
}
}
}
// Matrices
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_MATRICES))
{
angle::Mat4 proj = gles1State.mProjectionMatrices.back();
setUniformMatrix4fv(programObject, mProgramState.projMatrixLoc, 1, GL_FALSE, proj.data());
angle::Mat4 modelview = gles1State.mModelviewMatrices.back();
setUniformMatrix4fv(programObject, mProgramState.modelviewMatrixLoc, 1, GL_FALSE,
modelview.data());
angle::Mat4 modelviewInvTr = modelview.transpose().inverse();
setUniformMatrix4fv(programObject, mProgramState.modelviewInvTrLoc, 1, GL_FALSE,
modelviewInvTr.data());
Mat4Uniform *textureMatrixBuffer = uniformBuffers.textureMatrices.data();
for (int i = 0; i < kTexUnitCount; i++)
{
angle::Mat4 textureMatrix = gles1State.mTextureMatrices[i].back();
memcpy(textureMatrixBuffer + i, textureMatrix.data(), sizeof(Mat4Uniform));
}
setUniformMatrix4fv(programObject, mProgramState.textureMatrixLoc, kTexUnitCount, GL_FALSE,
reinterpret_cast<float *>(uniformBuffers.textureMatrices.data()));
}
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_TEXTURE_ENVIRONMENT))
{
for (int i = 0; i < kTexUnitCount; i++)
{
const auto &env = gles1State.textureEnvironment(i);
uniformBuffers.texEnvModes[i] = ToGLenum(env.mode);
uniformBuffers.texCombineRgbs[i] = ToGLenum(env.combineRgb);
uniformBuffers.texCombineAlphas[i] = ToGLenum(env.combineAlpha);
uniformBuffers.texCombineSrc0Rgbs[i] = ToGLenum(env.src0Rgb);
uniformBuffers.texCombineSrc0Alphas[i] = ToGLenum(env.src0Alpha);
uniformBuffers.texCombineSrc1Rgbs[i] = ToGLenum(env.src1Rgb);
uniformBuffers.texCombineSrc1Alphas[i] = ToGLenum(env.src1Alpha);
uniformBuffers.texCombineSrc2Rgbs[i] = ToGLenum(env.src2Rgb);
uniformBuffers.texCombineSrc2Alphas[i] = ToGLenum(env.src2Alpha);
uniformBuffers.texCombineOp0Rgbs[i] = ToGLenum(env.op0Rgb);
uniformBuffers.texCombineOp0Alphas[i] = ToGLenum(env.op0Alpha);
uniformBuffers.texCombineOp1Rgbs[i] = ToGLenum(env.op1Rgb);
uniformBuffers.texCombineOp1Alphas[i] = ToGLenum(env.op1Alpha);
uniformBuffers.texCombineOp2Rgbs[i] = ToGLenum(env.op2Rgb);
uniformBuffers.texCombineOp2Alphas[i] = ToGLenum(env.op2Alpha);
uniformBuffers.texEnvColors[i][0] = env.color.red;
uniformBuffers.texEnvColors[i][1] = env.color.green;
uniformBuffers.texEnvColors[i][2] = env.color.blue;
uniformBuffers.texEnvColors[i][3] = env.color.alpha;
uniformBuffers.texEnvRgbScales[i] = env.rgbScale;
uniformBuffers.texEnvAlphaScales[i] = env.alphaScale;
uniformBuffers.pointSpriteCoordReplaces[i] = env.pointSpriteCoordReplace;
}
setUniform1iv(context, programObject, mProgramState.textureEnvModeLoc, kTexUnitCount,
uniformBuffers.texEnvModes.data());
setUniform1iv(context, programObject, mProgramState.combineRgbLoc, kTexUnitCount,
uniformBuffers.texCombineRgbs.data());
setUniform1iv(context, programObject, mProgramState.combineAlphaLoc, kTexUnitCount,
uniformBuffers.texCombineAlphas.data());
setUniform1iv(context, programObject, mProgramState.src0rgbLoc, kTexUnitCount,
uniformBuffers.texCombineSrc0Rgbs.data());
setUniform1iv(context, programObject, mProgramState.src0alphaLoc, kTexUnitCount,
uniformBuffers.texCombineSrc0Alphas.data());
setUniform1iv(context, programObject, mProgramState.src1rgbLoc, kTexUnitCount,
uniformBuffers.texCombineSrc1Rgbs.data());
setUniform1iv(context, programObject, mProgramState.src1alphaLoc, kTexUnitCount,
uniformBuffers.texCombineSrc1Alphas.data());
setUniform1iv(context, programObject, mProgramState.src2rgbLoc, kTexUnitCount,
uniformBuffers.texCombineSrc2Rgbs.data());
setUniform1iv(context, programObject, mProgramState.src2alphaLoc, kTexUnitCount,
uniformBuffers.texCombineSrc2Alphas.data());
setUniform1iv(context, programObject, mProgramState.op0rgbLoc, kTexUnitCount,
uniformBuffers.texCombineOp0Rgbs.data());
setUniform1iv(context, programObject, mProgramState.op0alphaLoc, kTexUnitCount,
uniformBuffers.texCombineOp0Alphas.data());
setUniform1iv(context, programObject, mProgramState.op1rgbLoc, kTexUnitCount,
uniformBuffers.texCombineOp1Rgbs.data());
setUniform1iv(context, programObject, mProgramState.op1alphaLoc, kTexUnitCount,
uniformBuffers.texCombineOp1Alphas.data());
setUniform1iv(context, programObject, mProgramState.op2rgbLoc, kTexUnitCount,
uniformBuffers.texCombineOp2Rgbs.data());
setUniform1iv(context, programObject, mProgramState.op2alphaLoc, kTexUnitCount,
uniformBuffers.texCombineOp2Alphas.data());
setUniform4fv(programObject, mProgramState.textureEnvColorLoc, kTexUnitCount,
reinterpret_cast<float *>(uniformBuffers.texEnvColors.data()));
setUniform1fv(programObject, mProgramState.rgbScaleLoc, kTexUnitCount,
uniformBuffers.texEnvRgbScales.data());
setUniform1fv(programObject, mProgramState.alphaScaleLoc, kTexUnitCount,
uniformBuffers.texEnvAlphaScales.data());
setUniform1iv(context, programObject, mProgramState.pointSpriteCoordReplaceLoc,
kTexUnitCount, uniformBuffers.pointSpriteCoordReplaces.data());
}
// Alpha test
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_ALPHA_TEST))
{
setUniform1i(context, programObject, mProgramState.alphaFuncLoc,
ToGLenum(gles1State.mAlphaTestFunc));
setUniform1f(programObject, mProgramState.alphaTestRefLoc, gles1State.mAlphaTestRef);
}
// Shading, materials, and lighting
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_SHADE_MODEL))
{
setUniform1i(context, programObject, mProgramState.shadeModelFlatLoc,
gles1State.mShadeModel == ShadingModel::Flat);
}
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_MATERIAL))
{
const auto &material = gles1State.mMaterial;
setUniform4fv(programObject, mProgramState.materialAmbientLoc, 1, material.ambient.data());
setUniform4fv(programObject, mProgramState.materialDiffuseLoc, 1, material.diffuse.data());
setUniform4fv(programObject, mProgramState.materialSpecularLoc, 1,
material.specular.data());
setUniform4fv(programObject, mProgramState.materialEmissiveLoc, 1,
material.emissive.data());
setUniform1f(programObject, mProgramState.materialSpecularExponentLoc,
material.specularExponent);
}
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_LIGHTS))
{
const auto &lightModel = gles1State.mLightModel;
setUniform4fv(programObject, mProgramState.lightModelSceneAmbientLoc, 1,
lightModel.color.data());
// TODO (lfy@google.com): Implement two-sided lighting model
// gl->uniform1i(mProgramState.lightModelTwoSidedLoc, lightModel.twoSided);
for (int i = 0; i < kLightCount; i++)
{
const auto &light = gles1State.mLights[i];
uniformBuffers.lightEnables[i] = light.enabled;
memcpy(uniformBuffers.lightAmbients.data() + i, light.ambient.data(),
sizeof(Vec4Uniform));
memcpy(uniformBuffers.lightDiffuses.data() + i, light.diffuse.data(),
sizeof(Vec4Uniform));
memcpy(uniformBuffers.lightSpeculars.data() + i, light.specular.data(),
sizeof(Vec4Uniform));
memcpy(uniformBuffers.lightPositions.data() + i, light.position.data(),
sizeof(Vec4Uniform));
memcpy(uniformBuffers.lightDirections.data() + i, light.direction.data(),
sizeof(Vec3Uniform));
uniformBuffers.spotlightExponents[i] = light.spotlightExponent;
uniformBuffers.spotlightCutoffAngles[i] = light.spotlightCutoffAngle;
uniformBuffers.attenuationConsts[i] = light.attenuationConst;
uniformBuffers.attenuationLinears[i] = light.attenuationLinear;
uniformBuffers.attenuationQuadratics[i] = light.attenuationQuadratic;
}
setUniform1iv(context, programObject, mProgramState.lightEnablesLoc, kLightCount,
uniformBuffers.lightEnables.data());
setUniform4fv(programObject, mProgramState.lightAmbientsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.lightAmbients.data()));
setUniform4fv(programObject, mProgramState.lightDiffusesLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.lightDiffuses.data()));
setUniform4fv(programObject, mProgramState.lightSpecularsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.lightSpeculars.data()));
setUniform4fv(programObject, mProgramState.lightPositionsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.lightPositions.data()));
setUniform3fv(programObject, mProgramState.lightDirectionsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.lightDirections.data()));
setUniform1fv(programObject, mProgramState.lightSpotlightExponentsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.spotlightExponents.data()));
setUniform1fv(programObject, mProgramState.lightSpotlightCutoffAnglesLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.spotlightCutoffAngles.data()));
setUniform1fv(programObject, mProgramState.lightAttenuationConstsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.attenuationConsts.data()));
setUniform1fv(programObject, mProgramState.lightAttenuationLinearsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.attenuationLinears.data()));
setUniform1fv(programObject, mProgramState.lightAttenuationQuadraticsLoc, kLightCount,
reinterpret_cast<float *>(uniformBuffers.attenuationQuadratics.data()));
}
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_FOG))
{
const FogParameters &fog = gles1State.fogParameters();
setUniform1i(context, programObject, mProgramState.fogModeLoc, ToGLenum(fog.mode));
setUniform1f(programObject, mProgramState.fogDensityLoc, fog.density);
setUniform1f(programObject, mProgramState.fogStartLoc, fog.start);
setUniform1f(programObject, mProgramState.fogEndLoc, fog.end);
setUniform4fv(programObject, mProgramState.fogColorLoc, 1, fog.color.data());
}
// Clip planes
if (gles1State.isDirty(GLES1State::DIRTY_GLES1_CLIP_PLANES))
{
bool enableClipPlanes = false;
for (int i = 0; i < kClipPlaneCount; i++)
{
uniformBuffers.clipPlaneEnables[i] = glState->getEnableFeature(GL_CLIP_PLANE0 + i);
enableClipPlanes = enableClipPlanes || uniformBuffers.clipPlaneEnables[i];
gles1State.getClipPlane(
i, reinterpret_cast<float *>(uniformBuffers.clipPlanes.data() + i));
}
setUniform1i(context, programObject, mProgramState.enableClipPlanesLoc, enableClipPlanes);
setUniform1iv(context, programObject, mProgramState.clipPlaneEnablesLoc, kClipPlaneCount,
uniformBuffers.clipPlaneEnables.data());
setUniform4fv(programObject, mProgramState.clipPlanesLoc, kClipPlaneCount,
reinterpret_cast<float *>(uniformBuffers.clipPlanes.data()));
}
// Point rasterization
{
const PointParameters &pointParams = gles1State.mPointParameters;
setUniform1i(context, programObject, mProgramState.pointRasterizationLoc,
mode == PrimitiveMode::Points);
setUniform1i(context, programObject, mProgramState.pointSpriteEnabledLoc,
glState->getEnableFeature(GL_POINT_SPRITE_OES));
setUniform1f(programObject, mProgramState.pointSizeMinLoc, pointParams.pointSizeMin);
setUniform1f(programObject, mProgramState.pointSizeMaxLoc, pointParams.pointSizeMax);
setUniform3fv(programObject, mProgramState.pointDistanceAttenuationLoc, 1,
pointParams.pointDistanceAttenuation.data());
}
// Draw texture
{
setUniform1i(context, programObject, mProgramState.enableDrawTextureLoc,
mDrawTextureEnabled ? 1 : 0);
setUniform4fv(programObject, mProgramState.drawTextureCoordsLoc, 1, mDrawTextureCoords);
setUniform2fv(programObject, mProgramState.drawTextureDimsLoc, 1, mDrawTextureDims);
}
gles1State.clearDirty();
// None of those are changes in sampler, so there is no need to set the GL_PROGRAM dirty.
// Otherwise, put the dirtying here.
return angle::Result::Continue;
}
// static
int GLES1Renderer::VertexArrayIndex(ClientVertexArrayType type, const GLES1State &gles1)
{
switch (type)
{
case ClientVertexArrayType::Vertex:
return kVertexAttribIndex;
case ClientVertexArrayType::Normal:
return kNormalAttribIndex;
case ClientVertexArrayType::Color:
return kColorAttribIndex;
case ClientVertexArrayType::PointSize:
return kPointSizeAttribIndex;
case ClientVertexArrayType::TextureCoord:
return kTextureCoordAttribIndexBase + gles1.getClientTextureUnit();
default:
UNREACHABLE();
return 0;
}
}
// static
int GLES1Renderer::TexCoordArrayIndex(unsigned int unit)
{
return kTextureCoordAttribIndexBase + unit;
}
void GLES1Renderer::drawTexture(Context *context,
State *glState,
float x,
float y,
float z,
float width,
float height)
{
// get viewport
const gl::Rectangle &viewport = glState->getViewport();
// Translate from viewport to NDC for feeding the shader.
// Recenter, rescale. (e.g., [0, 0, 1080, 1920] -> [-1, -1, 1, 1])
float xNdc = scaleScreenCoordinateToNdc(x, static_cast<GLfloat>(viewport.width));
float yNdc = scaleScreenCoordinateToNdc(y, static_cast<GLfloat>(viewport.height));
float wNdc = scaleScreenDimensionToNdc(width, static_cast<GLfloat>(viewport.width));
float hNdc = scaleScreenDimensionToNdc(height, static_cast<GLfloat>(viewport.height));
float zNdc = 2.0f * clamp(z, 0.0f, 1.0f) - 1.0f;
mDrawTextureCoords[0] = xNdc;
mDrawTextureCoords[1] = yNdc;
mDrawTextureCoords[2] = zNdc;
mDrawTextureDims[0] = wNdc;
mDrawTextureDims[1] = hNdc;
mDrawTextureEnabled = true;
AttributesMask prevAttributesMask = glState->gles1().getVertexArraysAttributeMask();
setAttributesEnabled(context, glState, AttributesMask());
glState->gles1().setAllDirty();
context->drawArrays(PrimitiveMode::Triangles, 0, 6);
setAttributesEnabled(context, glState, prevAttributesMask);
mDrawTextureEnabled = false;
}
Shader *GLES1Renderer::getShader(GLuint handle) const
{
return mShaderPrograms->getShader(handle);
}
Program *GLES1Renderer::getProgram(GLuint handle) const
{
return mShaderPrograms->getProgram(handle);
}
angle::Result GLES1Renderer::compileShader(Context *context,
ShaderType shaderType,
const char *src,
GLuint *shaderOut)
{
rx::ContextImpl *implementation = context->getImplementation();
const Limitations &limitations = implementation->getNativeLimitations();
GLuint shader = mShaderPrograms->createShader(implementation, limitations, shaderType);
Shader *shaderObject = getShader(shader);
ANGLE_CHECK(context, shaderObject, "Missing shader object", GL_INVALID_OPERATION);
shaderObject->setSource(1, &src, nullptr);
shaderObject->compile(context);
*shaderOut = shader;
if (!shaderObject->isCompiled())
{
GLint infoLogLength = shaderObject->getInfoLogLength();
std::vector<char> infoLog(infoLogLength, 0);
shaderObject->getInfoLog(infoLogLength - 1, nullptr, infoLog.data());
ERR() << "Internal GLES 1 shader compile failed. Info log: " << infoLog.data();
ANGLE_CHECK(context, false, "GLES1Renderer shader compile failed.", GL_INVALID_OPERATION);
return angle::Result::Stop;
}
return angle::Result::Continue;
}
angle::Result GLES1Renderer::linkProgram(Context *context,
State *glState,
GLuint vertexShader,
GLuint fragmentShader,
const std::unordered_map<GLint, std::string> &attribLocs,
GLuint *programOut)
{
GLuint program = mShaderPrograms->createProgram(context->getImplementation());
Program *programObject = getProgram(program);
ANGLE_CHECK(context, programObject, "Missing program object", GL_INVALID_OPERATION);
*programOut = program;
programObject->attachShader(getShader(vertexShader));
programObject->attachShader(getShader(fragmentShader));
for (auto it : attribLocs)
{
GLint index = it.first;
const std::string &name = it.second;
programObject->bindAttributeLocation(index, name.c_str());
}
ANGLE_TRY(programObject->link(context));
programObject->resolveLink(context);
ANGLE_TRY(glState->onProgramExecutableChange(context, programObject));
if (!programObject->isLinked())
{
GLint infoLogLength = programObject->getInfoLogLength();
std::vector<char> infoLog(infoLogLength, 0);
programObject->getInfoLog(infoLogLength - 1, nullptr, infoLog.data());
ERR() << "Internal GLES 1 shader link failed. Info log: " << infoLog.data();
ANGLE_CHECK(context, false, "GLES1Renderer program link failed.", GL_INVALID_OPERATION);
return angle::Result::Stop;
}
programObject->detachShader(context, getShader(vertexShader));
programObject->detachShader(context, getShader(fragmentShader));
return angle::Result::Continue;
}
angle::Result GLES1Renderer::initializeRendererProgram(Context *context, State *glState)
{
if (mRendererProgramInitialized)
{
return angle::Result::Continue;
}
mShaderPrograms = new ShaderProgramManager();
GLuint vertexShader;
GLuint fragmentShader;
ANGLE_TRY(compileShader(context, ShaderType::Vertex, kGLES1DrawVShader, &vertexShader));
std::stringstream fragmentStream;
fragmentStream << kGLES1DrawFShaderHeader;
fragmentStream << kGLES1DrawFShaderUniformDefs;
fragmentStream << kGLES1DrawFShaderFunctions;
fragmentStream << kGLES1DrawFShaderMultitexturing;
fragmentStream << kGLES1DrawFShaderMain;
ANGLE_TRY(compileShader(context, ShaderType::Fragment, fragmentStream.str().c_str(),
&fragmentShader));
std::unordered_map<GLint, std::string> attribLocs;
attribLocs[(GLint)kVertexAttribIndex] = "pos";
attribLocs[(GLint)kNormalAttribIndex] = "normal";
attribLocs[(GLint)kColorAttribIndex] = "color";
attribLocs[(GLint)kPointSizeAttribIndex] = "pointsize";
for (int i = 0; i < kTexUnitCount; i++)
{
std::stringstream ss;
ss << "texcoord" << i;
attribLocs[kTextureCoordAttribIndexBase + i] = ss.str();
}
ANGLE_TRY(linkProgram(context, glState, vertexShader, fragmentShader, attribLocs,
&mProgramState.program));
mShaderPrograms->deleteShader(context, vertexShader);
mShaderPrograms->deleteShader(context, fragmentShader);
Program *programObject = getProgram(mProgramState.program);
mProgramState.projMatrixLoc = programObject->getUniformLocation("projection");
mProgramState.modelviewMatrixLoc = programObject->getUniformLocation("modelview");
mProgramState.textureMatrixLoc = programObject->getUniformLocation("texture_matrix");
mProgramState.modelviewInvTrLoc = programObject->getUniformLocation("modelview_invtr");
for (int i = 0; i < kTexUnitCount; i++)
{
std::stringstream ss2d;
std::stringstream sscube;
ss2d << "tex_sampler" << i;
sscube << "tex_cube_sampler" << i;
mProgramState.tex2DSamplerLocs[i] = programObject->getUniformLocation(ss2d.str().c_str());
mProgramState.texCubeSamplerLocs[i] =
programObject->getUniformLocation(sscube.str().c_str());
}
mProgramState.enableTexture2DLoc = programObject->getUniformLocation("enable_texture_2d");
mProgramState.enableTextureCubeMapLoc =
programObject->getUniformLocation("enable_texture_cube_map");
mProgramState.textureFormatLoc = programObject->getUniformLocation("texture_format");
mProgramState.textureEnvModeLoc = programObject->getUniformLocation("texture_env_mode");
mProgramState.combineRgbLoc = programObject->getUniformLocation("combine_rgb");
mProgramState.combineAlphaLoc = programObject->getUniformLocation("combine_alpha");
mProgramState.src0rgbLoc = programObject->getUniformLocation("src0_rgb");
mProgramState.src0alphaLoc = programObject->getUniformLocation("src0_alpha");
mProgramState.src1rgbLoc = programObject->getUniformLocation("src1_rgb");
mProgramState.src1alphaLoc = programObject->getUniformLocation("src1_alpha");
mProgramState.src2rgbLoc = programObject->getUniformLocation("src2_rgb");
mProgramState.src2alphaLoc = programObject->getUniformLocation("src2_alpha");
mProgramState.op0rgbLoc = programObject->getUniformLocation("op0_rgb");
mProgramState.op0alphaLoc = programObject->getUniformLocation("op0_alpha");
mProgramState.op1rgbLoc = programObject->getUniformLocation("op1_rgb");
mProgramState.op1alphaLoc = programObject->getUniformLocation("op1_alpha");
mProgramState.op2rgbLoc = programObject->getUniformLocation("op2_rgb");
mProgramState.op2alphaLoc = programObject->getUniformLocation("op2_alpha");
mProgramState.textureEnvColorLoc = programObject->getUniformLocation("texture_env_color");
mProgramState.rgbScaleLoc = programObject->getUniformLocation("texture_env_rgb_scale");
mProgramState.alphaScaleLoc = programObject->getUniformLocation("texture_env_alpha_scale");
mProgramState.pointSpriteCoordReplaceLoc =
programObject->getUniformLocation("point_sprite_coord_replace");
mProgramState.enableAlphaTestLoc = programObject->getUniformLocation("enable_alpha_test");
mProgramState.alphaFuncLoc = programObject->getUniformLocation("alpha_func");
mProgramState.alphaTestRefLoc = programObject->getUniformLocation("alpha_test_ref");
mProgramState.shadeModelFlatLoc = programObject->getUniformLocation("shade_model_flat");
mProgramState.enableLightingLoc = programObject->getUniformLocation("enable_lighting");
mProgramState.enableRescaleNormalLoc =
programObject->getUniformLocation("enable_rescale_normal");
mProgramState.enableNormalizeLoc = programObject->getUniformLocation("enable_normalize");
mProgramState.enableColorMaterialLoc =
programObject->getUniformLocation("enable_color_material");
mProgramState.materialAmbientLoc = programObject->getUniformLocation("material_ambient");
mProgramState.materialDiffuseLoc = programObject->getUniformLocation("material_diffuse");
mProgramState.materialSpecularLoc = programObject->getUniformLocation("material_specular");
mProgramState.materialEmissiveLoc = programObject->getUniformLocation("material_emissive");
mProgramState.materialSpecularExponentLoc =
programObject->getUniformLocation("material_specular_exponent");
mProgramState.lightModelSceneAmbientLoc =
programObject->getUniformLocation("light_model_scene_ambient");
mProgramState.lightModelTwoSidedLoc =
programObject->getUniformLocation("light_model_two_sided");
mProgramState.lightEnablesLoc = programObject->getUniformLocation("light_enables");
mProgramState.lightAmbientsLoc = programObject->getUniformLocation("light_ambients");
mProgramState.lightDiffusesLoc = programObject->getUniformLocation("light_diffuses");
mProgramState.lightSpecularsLoc = programObject->getUniformLocation("light_speculars");
mProgramState.lightPositionsLoc = programObject->getUniformLocation("light_positions");
mProgramState.lightDirectionsLoc = programObject->getUniformLocation("light_directions");
mProgramState.lightSpotlightExponentsLoc =
programObject->getUniformLocation("light_spotlight_exponents");
mProgramState.lightSpotlightCutoffAnglesLoc =
programObject->getUniformLocation("light_spotlight_cutoff_angles");
mProgramState.lightAttenuationConstsLoc =
programObject->getUniformLocation("light_attenuation_consts");
mProgramState.lightAttenuationLinearsLoc =
programObject->getUniformLocation("light_attenuation_linears");
mProgramState.lightAttenuationQuadraticsLoc =
programObject->getUniformLocation("light_attenuation_quadratics");
mProgramState.fogEnableLoc = programObject->getUniformLocation("enable_fog");
mProgramState.fogModeLoc = programObject->getUniformLocation("fog_mode");
mProgramState.fogDensityLoc = programObject->getUniformLocation("fog_density");
mProgramState.fogStartLoc = programObject->getUniformLocation("fog_start");
mProgramState.fogEndLoc = programObject->getUniformLocation("fog_end");
mProgramState.fogColorLoc = programObject->getUniformLocation("fog_color");
mProgramState.enableClipPlanesLoc = programObject->getUniformLocation("enable_clip_planes");
mProgramState.clipPlaneEnablesLoc = programObject->getUniformLocation("clip_plane_enables");
mProgramState.clipPlanesLoc = programObject->getUniformLocation("clip_planes");
mProgramState.pointRasterizationLoc = programObject->getUniformLocation("point_rasterization");
mProgramState.pointSizeMinLoc = programObject->getUniformLocation("point_size_min");
mProgramState.pointSizeMaxLoc = programObject->getUniformLocation("point_size_max");
mProgramState.pointDistanceAttenuationLoc =
programObject->getUniformLocation("point_distance_attenuation");
mProgramState.pointSpriteEnabledLoc = programObject->getUniformLocation("point_sprite_enabled");
mProgramState.enableDrawTextureLoc = programObject->getUniformLocation("enable_draw_texture");
mProgramState.drawTextureCoordsLoc = programObject->getUniformLocation("draw_texture_coords");
mProgramState.drawTextureDimsLoc = programObject->getUniformLocation("draw_texture_dims");
mProgramState.drawTextureNormalizedCropRectLoc =
programObject->getUniformLocation("draw_texture_normalized_crop_rect");
ANGLE_TRY(glState->setProgram(context, programObject));
for (int i = 0; i < kTexUnitCount; i++)
{
setUniform1i(context, programObject, mProgramState.tex2DSamplerLocs[i], i);
setUniform1i(context, programObject, mProgramState.texCubeSamplerLocs[i],
i + kTexUnitCount);
}
glState->setObjectDirty(GL_PROGRAM);
mRendererProgramInitialized = true;
return angle::Result::Continue;
}
void GLES1Renderer::setUniform1i(Context *context, Program *programObject, GLint loc, GLint value)
{
if (loc == -1)
return;
programObject->setUniform1iv(context, loc, 1, &value);
}
void GLES1Renderer::setUniform1iv(Context *context,
Program *programObject,
GLint loc,
GLint count,
const GLint *value)
{
if (loc == -1)
return;
programObject->setUniform1iv(context, loc, count, value);
}
void GLES1Renderer::setUniformMatrix4fv(Program *programObject,
GLint loc,
GLint count,
GLboolean transpose,
const GLfloat *value)
{
if (loc == -1)
return;
programObject->setUniformMatrix4fv(loc, count, transpose, value);
}
void GLES1Renderer::setUniform4fv(Program *programObject,
GLint loc,
GLint count,
const GLfloat *value)
{
if (loc == -1)
return;
programObject->setUniform4fv(loc, count, value);
}
void GLES1Renderer::setUniform3fv(Program *programObject,
GLint loc,
GLint count,
const GLfloat *value)
{
if (loc == -1)
return;
programObject->setUniform3fv(loc, count, value);
}
void GLES1Renderer::setUniform2fv(Program *programObject,
GLint loc,
GLint count,
const GLfloat *value)
{
if (loc == -1)
return;
programObject->setUniform2fv(loc, count, value);
}
void GLES1Renderer::setUniform1f(Program *programObject, GLint loc, GLfloat value)
{
if (loc == -1)
return;
programObject->setUniform1fv(loc, 1, &value);
}
void GLES1Renderer::setUniform1fv(Program *programObject,
GLint loc,
GLint count,
const GLfloat *value)
{
if (loc == -1)
return;
programObject->setUniform1fv(loc, count, value);
}
void GLES1Renderer::setAttributesEnabled(Context *context, State *glState, AttributesMask mask)
{
GLES1State &gles1 = glState->gles1();
ClientVertexArrayType nonTexcoordArrays[] = {
ClientVertexArrayType::Vertex,
ClientVertexArrayType::Normal,
ClientVertexArrayType::Color,
ClientVertexArrayType::PointSize,
};
for (const ClientVertexArrayType attrib : nonTexcoordArrays)
{
int index = VertexArrayIndex(attrib, glState->gles1());
if (mask.test(index))
{
gles1.setClientStateEnabled(attrib, true);
context->enableVertexAttribArray(index);
}
else
{
gles1.setClientStateEnabled(attrib, false);
context->disableVertexAttribArray(index);
}
}
for (unsigned int i = 0; i < kTexUnitCount; i++)
{
int index = TexCoordArrayIndex(i);
if (mask.test(index))
{
gles1.setTexCoordArrayEnabled(i, true);
context->enableVertexAttribArray(index);
}
else
{
gles1.setTexCoordArrayEnabled(i, false);
context->disableVertexAttribArray(index);
}
}
}
} // namespace gl