summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp1197
1 files changed, 1197 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp b/gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp
new file mode 100644
index 0000000000..4ca3d47189
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/GLES1Renderer.cpp
@@ -0,0 +1,1197 @@
+//
+// 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 "common/hash_utils.h"
+#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"
+
+uint32_t GetLogicOpUniform(const gl::FramebufferAttachment *color, gl::LogicalOperation logicOp)
+{
+ const uint32_t red = color->getRedSize();
+ const uint32_t green = color->getGreenSize();
+ const uint32_t blue = color->getBlueSize();
+ const uint32_t alpha = color->getAlphaSize();
+
+ ASSERT(red <= 8 && green <= 8 && blue <= 8 && alpha <= 8);
+
+ return red | green << 4 | blue << 8 | alpha << 12 | static_cast<uint32_t>(logicOp) << 16;
+}
+} // anonymous namespace
+
+namespace gl
+{
+GLES1ShaderState::GLES1ShaderState() = default;
+GLES1ShaderState::~GLES1ShaderState() = default;
+GLES1ShaderState::GLES1ShaderState(const GLES1ShaderState &other)
+{
+ memcpy(this, &other, sizeof(GLES1ShaderState));
+}
+
+bool operator==(const GLES1ShaderState &a, const GLES1ShaderState &b)
+{
+ return memcmp(&a, &b, sizeof(GLES1ShaderState)) == 0;
+}
+bool operator!=(const GLES1ShaderState &a, const GLES1ShaderState &b)
+{
+ return !(a == b);
+}
+
+size_t GLES1ShaderState::hash() const
+{
+ return angle::ComputeGenericHash(*this);
+}
+
+GLES1Renderer::GLES1Renderer() : mRendererProgramInitialized(false) {}
+
+void GLES1Renderer::onDestroy(Context *context, State *state)
+{
+ if (mRendererProgramInitialized)
+ {
+ (void)state->setProgram(context, 0);
+
+ for (const auto &iter : mUberShaderState)
+ {
+ const GLES1UberShaderState &UberShaderState = iter.second;
+ mShaderPrograms->deleteProgram(context, {UberShaderState.programState.program});
+ }
+ mShaderPrograms->release(context);
+ mShaderPrograms = nullptr;
+ mRendererProgramInitialized = false;
+ }
+}
+
+GLES1Renderer::~GLES1Renderer() = default;
+
+angle::Result GLES1Renderer::prepareForDraw(PrimitiveMode mode, Context *context, State *glState)
+{
+ GLES1State &gles1State = glState->gles1();
+
+ GLES1ShaderState::BoolTexArray &tex2DEnables = mShaderState.tex2DEnables;
+ GLES1ShaderState::BoolTexArray &texCubeEnables = mShaderState.texCubeEnables;
+ GLES1ShaderState::IntTexArray &tex2DFormats = mShaderState.tex2DFormats;
+
+ 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);
+ }
+
+ Texture *currCubeTexture = glState->getSamplerTexture(i, TextureType::CubeMap);
+
+ // > If texturing is enabled for a texture unit at the time a primitive is rasterized, if
+ // > TEXTURE MIN FILTER is one that requires a mipmap, and if the texture image bound to the
+ // > enabled texture target is not complete, then it is as if texture mapping were disabled
+ // > for that texture unit.
+ if (tex2DEnables[i] && curr2DTexture && IsMipmapFiltered(curr2DTexture->getMinFilter()))
+ {
+ tex2DEnables[i] = curr2DTexture->isMipmapComplete();
+ }
+ if (texCubeEnables[i] && currCubeTexture &&
+ IsMipmapFiltered(currCubeTexture->getMinFilter()))
+ {
+ texCubeEnables[i] = curr2DTexture->isMipmapComplete();
+ }
+ }
+
+ GLES1ShaderState::IntTexArray &texEnvModes = mShaderState.texEnvModes;
+ GLES1ShaderState::IntTexArray &texCombineRgbs = mShaderState.texCombineRgbs;
+ GLES1ShaderState::IntTexArray &texCombineAlphas = mShaderState.texCombineAlphas;
+ GLES1ShaderState::IntTexArray &texCombineSrc0Rgbs = mShaderState.texCombineSrc0Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineSrc0Alphas = mShaderState.texCombineSrc0Alphas;
+ GLES1ShaderState::IntTexArray &texCombineSrc1Rgbs = mShaderState.texCombineSrc1Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineSrc1Alphas = mShaderState.texCombineSrc1Alphas;
+ GLES1ShaderState::IntTexArray &texCombineSrc2Rgbs = mShaderState.texCombineSrc2Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineSrc2Alphas = mShaderState.texCombineSrc2Alphas;
+ GLES1ShaderState::IntTexArray &texCombineOp0Rgbs = mShaderState.texCombineOp0Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineOp0Alphas = mShaderState.texCombineOp0Alphas;
+ GLES1ShaderState::IntTexArray &texCombineOp1Rgbs = mShaderState.texCombineOp1Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineOp1Alphas = mShaderState.texCombineOp1Alphas;
+ GLES1ShaderState::IntTexArray &texCombineOp2Rgbs = mShaderState.texCombineOp2Rgbs;
+ GLES1ShaderState::IntTexArray &texCombineOp2Alphas = mShaderState.texCombineOp2Alphas;
+
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_TEXTURE_ENVIRONMENT))
+ {
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ const auto &env = gles1State.textureEnvironment(i);
+ texEnvModes[i] = ToGLenum(env.mode);
+ texCombineRgbs[i] = ToGLenum(env.combineRgb);
+ texCombineAlphas[i] = ToGLenum(env.combineAlpha);
+ texCombineSrc0Rgbs[i] = ToGLenum(env.src0Rgb);
+ texCombineSrc0Alphas[i] = ToGLenum(env.src0Alpha);
+ texCombineSrc1Rgbs[i] = ToGLenum(env.src1Rgb);
+ texCombineSrc1Alphas[i] = ToGLenum(env.src1Alpha);
+ texCombineSrc2Rgbs[i] = ToGLenum(env.src2Rgb);
+ texCombineSrc2Alphas[i] = ToGLenum(env.src2Alpha);
+ texCombineOp0Rgbs[i] = ToGLenum(env.op0Rgb);
+ texCombineOp0Alphas[i] = ToGLenum(env.op0Alpha);
+ texCombineOp1Rgbs[i] = ToGLenum(env.op1Rgb);
+ texCombineOp1Alphas[i] = ToGLenum(env.op1Alpha);
+ texCombineOp2Rgbs[i] = ToGLenum(env.op2Rgb);
+ texCombineOp2Alphas[i] = ToGLenum(env.op2Alpha);
+ }
+ }
+
+ bool enableClipPlanes = false;
+ GLES1ShaderState::BoolClipPlaneArray &clipPlaneEnables = mShaderState.clipPlaneEnables;
+ for (int i = 0; i < kClipPlaneCount; i++)
+ {
+ clipPlaneEnables[i] = glState->getEnableFeature(GL_CLIP_PLANE0 + i);
+ enableClipPlanes = enableClipPlanes || clipPlaneEnables[i];
+ }
+
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::ClipPlanes] = enableClipPlanes;
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::DrawTexture] = mDrawTextureEnabled;
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::PointRasterization] =
+ mode == PrimitiveMode::Points;
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::ShadeModelFlat] =
+ gles1State.mShadeModel == ShadingModel::Flat;
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::AlphaTest] =
+ glState->getEnableFeature(GL_ALPHA_TEST);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::Lighting] =
+ glState->getEnableFeature(GL_LIGHTING);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::RescaleNormal] =
+ glState->getEnableFeature(GL_RESCALE_NORMAL);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::Normalize] =
+ glState->getEnableFeature(GL_NORMALIZE);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::Fog] = glState->getEnableFeature(GL_FOG);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::PointSprite] =
+ glState->getEnableFeature(GL_POINT_SPRITE_OES);
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::ColorMaterial] =
+ glState->getEnableFeature(GL_COLOR_MATERIAL);
+
+ // TODO (lfy@google.com): Implement two-sided lighting model (lightModel.twoSided)
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::LightModelTwoSided] = false;
+
+ GLES1ShaderState::BoolTexArray &pointSpriteCoordReplaces =
+ mShaderState.pointSpriteCoordReplaces;
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ const auto &env = gles1State.textureEnvironment(i);
+ pointSpriteCoordReplaces[i] = env.pointSpriteCoordReplace;
+ }
+
+ GLES1ShaderState::BoolLightArray &lightEnables = mShaderState.lightEnables;
+ for (int i = 0; i < kLightCount; i++)
+ {
+ const auto &light = gles1State.mLights[i];
+ lightEnables[i] = light.enabled;
+ }
+
+ mShaderState.alphaTestFunc = gles1State.mAlphaTestFunc;
+ mShaderState.fogMode = gles1State.fogParameters().mode;
+
+ const bool hasLogicOpANGLE = context->getExtensions().logicOpANGLE;
+ const bool hasFramebufferFetch = context->getExtensions().shaderFramebufferFetchEXT ||
+ context->getExtensions().shaderFramebufferFetchNonCoherentEXT;
+
+ if (!hasLogicOpANGLE && hasFramebufferFetch)
+ {
+ mShaderState.mGLES1StateEnabled[GLES1StateEnables::LogicOpThroughFramebufferFetch] =
+ gles1State.mLogicOpEnabled;
+ }
+
+ // All the states set before this spot affect ubershader creation
+
+ ANGLE_TRY(initializeRendererProgram(context, glState));
+
+ GLES1UberShaderState UberShaderState = getUberShaderState();
+
+ const GLES1ProgramState &programState = UberShaderState.programState;
+ GLES1UniformBuffers &uniformBuffers = UberShaderState.uniformBuffers;
+
+ Program *programObject = getProgram(programState.program);
+
+ // If anything is dirty in gles1 or the common parts of gles1/2, just redo these parts
+ // completely for now.
+
+ // Feature enables
+
+ // Texture unit enables and format info
+ std::array<Vec4Uniform, kTexUnitCount> texCropRects;
+ Vec4Uniform *cropRectBuffer = texCropRects.data();
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ Texture *curr2DTexture = glState->getSamplerTexture(i, TextureType::_2D);
+ if (curr2DTexture)
+ {
+ 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;
+ }
+ }
+ }
+ setUniform4fv(programObject, programState.drawTextureNormalizedCropRectLoc, kTexUnitCount,
+ reinterpret_cast<GLfloat *>(cropRectBuffer));
+
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_LOGIC_OP) && hasLogicOpANGLE)
+ {
+ context->setLogicOpEnabled(gles1State.mLogicOpEnabled);
+ context->setLogicOp(gles1State.mLogicOp);
+ }
+ else if (hasFramebufferFetch)
+ {
+ const Framebuffer *drawFramebuffer = glState->getDrawFramebuffer();
+ const FramebufferAttachment *colorAttachment = drawFramebuffer->getColorAttachment(0);
+
+ if (gles1State.mLogicOpEnabled)
+ {
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_LOGIC_OP))
+ {
+ // Set up uniform value for logic op
+ setUniform1ui(programObject, programState.logicOpLoc,
+ GetLogicOpUniform(colorAttachment, gles1State.mLogicOp));
+ }
+
+ // Issue a framebuffer fetch barrier if non-coherent
+ if (!context->getExtensions().shaderFramebufferFetchEXT)
+ {
+ context->framebufferFetchBarrier();
+ }
+ }
+ }
+
+ // 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, programState.projMatrixLoc, 1, GL_FALSE, proj.data());
+
+ angle::Mat4 modelview = gles1State.mModelviewMatrices.back();
+ setUniformMatrix4fv(programObject, programState.modelviewMatrixLoc, 1, GL_FALSE,
+ modelview.data());
+
+ angle::Mat4 modelviewInvTr = modelview.transpose().inverse();
+ setUniformMatrix4fv(programObject, programState.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, programState.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.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;
+ }
+
+ setUniform4fv(programObject, programState.textureEnvColorLoc, kTexUnitCount,
+ reinterpret_cast<float *>(uniformBuffers.texEnvColors.data()));
+ setUniform1fv(programObject, programState.rgbScaleLoc, kTexUnitCount,
+ uniformBuffers.texEnvRgbScales.data());
+ setUniform1fv(programObject, programState.alphaScaleLoc, kTexUnitCount,
+ uniformBuffers.texEnvAlphaScales.data());
+ }
+
+ // Alpha test
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_ALPHA_TEST))
+ {
+ setUniform1f(programObject, programState.alphaTestRefLoc, gles1State.mAlphaTestRef);
+ }
+
+ // Shading, materials, and lighting
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_MATERIAL))
+ {
+ const auto &material = gles1State.mMaterial;
+
+ setUniform4fv(programObject, programState.materialAmbientLoc, 1, material.ambient.data());
+ setUniform4fv(programObject, programState.materialDiffuseLoc, 1, material.diffuse.data());
+ setUniform4fv(programObject, programState.materialSpecularLoc, 1, material.specular.data());
+ setUniform4fv(programObject, programState.materialEmissiveLoc, 1, material.emissive.data());
+ setUniform1f(programObject, programState.materialSpecularExponentLoc,
+ material.specularExponent);
+ }
+
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_LIGHTS))
+ {
+ const auto &lightModel = gles1State.mLightModel;
+
+ setUniform4fv(programObject, programState.lightModelSceneAmbientLoc, 1,
+ lightModel.color.data());
+
+ for (int i = 0; i < kLightCount; i++)
+ {
+ const auto &light = gles1State.mLights[i];
+ 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;
+ }
+
+ setUniform4fv(programObject, programState.lightAmbientsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.lightAmbients.data()));
+ setUniform4fv(programObject, programState.lightDiffusesLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.lightDiffuses.data()));
+ setUniform4fv(programObject, programState.lightSpecularsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.lightSpeculars.data()));
+ setUniform4fv(programObject, programState.lightPositionsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.lightPositions.data()));
+ setUniform3fv(programObject, programState.lightDirectionsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.lightDirections.data()));
+ setUniform1fv(programObject, programState.lightSpotlightExponentsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.spotlightExponents.data()));
+ setUniform1fv(programObject, programState.lightSpotlightCutoffAnglesLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.spotlightCutoffAngles.data()));
+ setUniform1fv(programObject, programState.lightAttenuationConstsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.attenuationConsts.data()));
+ setUniform1fv(programObject, programState.lightAttenuationLinearsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.attenuationLinears.data()));
+ setUniform1fv(programObject, programState.lightAttenuationQuadraticsLoc, kLightCount,
+ reinterpret_cast<float *>(uniformBuffers.attenuationQuadratics.data()));
+ }
+
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_FOG))
+ {
+ const FogParameters &fog = gles1State.fogParameters();
+ setUniform1f(programObject, programState.fogDensityLoc, fog.density);
+ setUniform1f(programObject, programState.fogStartLoc, fog.start);
+ setUniform1f(programObject, programState.fogEndLoc, fog.end);
+ setUniform4fv(programObject, programState.fogColorLoc, 1, fog.color.data());
+ }
+
+ // Clip planes
+ if (gles1State.isDirty(GLES1State::DIRTY_GLES1_CLIP_PLANES))
+ {
+ for (int i = 0; i < kClipPlaneCount; i++)
+ {
+ gles1State.getClipPlane(
+ i, reinterpret_cast<float *>(uniformBuffers.clipPlanes.data() + i));
+ }
+
+ setUniform4fv(programObject, programState.clipPlanesLoc, kClipPlaneCount,
+ reinterpret_cast<float *>(uniformBuffers.clipPlanes.data()));
+ }
+
+ // Point rasterization
+ {
+ const PointParameters &pointParams = gles1State.mPointParameters;
+
+ setUniform1f(programObject, programState.pointSizeMinLoc, pointParams.pointSizeMin);
+ setUniform1f(programObject, programState.pointSizeMaxLoc, pointParams.pointSizeMax);
+ setUniform3fv(programObject, programState.pointDistanceAttenuationLoc, 1,
+ pointParams.pointDistanceAttenuation.data());
+ }
+
+ // Draw texture
+ {
+ setUniform4fv(programObject, programState.drawTextureCoordsLoc, 1, mDrawTextureCoords);
+ setUniform2fv(programObject, programState.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
+ClientVertexArrayType GLES1Renderer::VertexArrayType(int attribIndex)
+{
+ switch (attribIndex)
+ {
+ case kVertexAttribIndex:
+ return ClientVertexArrayType::Vertex;
+ case kNormalAttribIndex:
+ return ClientVertexArrayType::Normal;
+ case kColorAttribIndex:
+ return ClientVertexArrayType::Color;
+ case kPointSizeAttribIndex:
+ return ClientVertexArrayType::PointSize;
+ default:
+ if (attribIndex < kTextureCoordAttribIndexBase + kTexUnitCount)
+ {
+ return ClientVertexArrayType::TextureCoord;
+ }
+ UNREACHABLE();
+ return ClientVertexArrayType::InvalidEnum;
+ }
+}
+
+// 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(ShaderProgramID handle) const
+{
+ return mShaderPrograms->getShader(handle);
+}
+
+Program *GLES1Renderer::getProgram(ShaderProgramID handle) const
+{
+ return mShaderPrograms->getProgram(handle);
+}
+
+angle::Result GLES1Renderer::compileShader(Context *context,
+ ShaderType shaderType,
+ const char *src,
+ ShaderProgramID *shaderOut)
+{
+ rx::ContextImpl *implementation = context->getImplementation();
+ const Limitations &limitations = implementation->getNativeLimitations();
+
+ ShaderProgramID 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(context))
+ {
+ GLint infoLogLength = shaderObject->getInfoLogLength(context);
+ std::vector<char> infoLog(infoLogLength, 0);
+ shaderObject->getInfoLog(context, 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,
+ ShaderProgramID vertexShader,
+ ShaderProgramID fragmentShader,
+ const angle::HashMap<GLint, std::string> &attribLocs,
+ ShaderProgramID *programOut)
+{
+ ShaderProgramID 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->getExecutable().getInfoLogLength();
+ std::vector<char> infoLog(infoLogLength, 0);
+ programObject->getExecutable().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;
+}
+
+const char *GLES1Renderer::getShaderBool(GLES1StateEnables state)
+{
+ if (mShaderState.mGLES1StateEnabled[state])
+ {
+ return "true";
+ }
+ else
+ {
+ return "false";
+ }
+}
+
+void GLES1Renderer::addShaderDefine(std::stringstream &outStream,
+ GLES1StateEnables state,
+ const char *enableString)
+{
+ outStream << "\n";
+ outStream << "#define " << enableString << " " << getShaderBool(state);
+}
+
+void GLES1Renderer::addShaderInt(std::stringstream &outStream, const char *name, int value)
+{
+ outStream << "\n";
+ outStream << "const int " << name << " = " << value << ";";
+}
+
+void GLES1Renderer::addShaderIntTexArray(std::stringstream &outStream,
+ const char *texString,
+ GLES1ShaderState::IntTexArray &texState)
+{
+ outStream << "\n";
+ outStream << "const int " << texString << "[kMaxTexUnits] = int[kMaxTexUnits](";
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ if (i != 0)
+ {
+ outStream << ", ";
+ }
+ outStream << texState[i];
+ }
+ outStream << ");";
+}
+
+void GLES1Renderer::addShaderBoolTexArray(std::stringstream &outStream,
+ const char *name,
+ GLES1ShaderState::BoolTexArray &value)
+{
+ outStream << std::boolalpha;
+ outStream << "\n";
+ outStream << "bool " << name << "[kMaxTexUnits] = bool[kMaxTexUnits](";
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ if (i != 0)
+ {
+ outStream << ", ";
+ }
+ outStream << value[i];
+ }
+ outStream << ");";
+}
+
+void GLES1Renderer::addShaderBoolLightArray(std::stringstream &outStream,
+ const char *name,
+ GLES1ShaderState::BoolLightArray &value)
+{
+ outStream << std::boolalpha;
+ outStream << "\n";
+ outStream << "bool " << name << "[kMaxLights] = bool[kMaxLights](";
+ for (int i = 0; i < kLightCount; i++)
+ {
+ if (i != 0)
+ {
+ outStream << ", ";
+ }
+ outStream << value[i];
+ }
+ outStream << ");";
+}
+
+void GLES1Renderer::addShaderBoolClipPlaneArray(std::stringstream &outStream,
+ const char *name,
+ GLES1ShaderState::BoolClipPlaneArray &value)
+{
+ outStream << std::boolalpha;
+ outStream << "\n";
+ outStream << "bool " << name << "[kMaxClipPlanes] = bool[kMaxClipPlanes](";
+ for (int i = 0; i < kClipPlaneCount; i++)
+ {
+ if (i != 0)
+ {
+ outStream << ", ";
+ }
+ outStream << value[i];
+ }
+ outStream << ");";
+}
+
+void GLES1Renderer::addVertexShaderDefs(std::stringstream &outStream)
+{
+ addShaderDefine(outStream, GLES1StateEnables::Lighting, "enable_lighting");
+ addShaderDefine(outStream, GLES1StateEnables::ColorMaterial, "enable_color_material");
+ addShaderDefine(outStream, GLES1StateEnables::DrawTexture, "enable_draw_texture");
+ addShaderDefine(outStream, GLES1StateEnables::PointRasterization, "point_rasterization");
+ addShaderDefine(outStream, GLES1StateEnables::RescaleNormal, "enable_rescale_normal");
+ addShaderDefine(outStream, GLES1StateEnables::Normalize, "enable_normalize");
+ addShaderDefine(outStream, GLES1StateEnables::LightModelTwoSided, "light_model_two_sided");
+
+ // bool light_enables[kMaxLights] = bool[kMaxLights](...);
+ addShaderBoolLightArray(outStream, "light_enables", mShaderState.lightEnables);
+}
+
+void GLES1Renderer::addFragmentShaderDefs(std::stringstream &outStream)
+{
+ addShaderDefine(outStream, GLES1StateEnables::Fog, "enable_fog");
+ addShaderDefine(outStream, GLES1StateEnables::ClipPlanes, "enable_clip_planes");
+ addShaderDefine(outStream, GLES1StateEnables::DrawTexture, "enable_draw_texture");
+ addShaderDefine(outStream, GLES1StateEnables::PointRasterization, "point_rasterization");
+ addShaderDefine(outStream, GLES1StateEnables::PointSprite, "point_sprite_enabled");
+ addShaderDefine(outStream, GLES1StateEnables::AlphaTest, "enable_alpha_test");
+ addShaderDefine(outStream, GLES1StateEnables::ShadeModelFlat, "shade_model_flat");
+
+ // bool enable_texture_2d[kMaxTexUnits] = bool[kMaxTexUnits](...);
+ addShaderBoolTexArray(outStream, "enable_texture_2d", mShaderState.tex2DEnables);
+
+ // bool enable_texture_cube_map[kMaxTexUnits] = bool[kMaxTexUnits](...);
+ addShaderBoolTexArray(outStream, "enable_texture_cube_map", mShaderState.texCubeEnables);
+
+ // int texture_format[kMaxTexUnits] = int[kMaxTexUnits](...);
+ addShaderIntTexArray(outStream, "texture_format", mShaderState.tex2DFormats);
+
+ // bool point_sprite_coord_replace[kMaxTexUnits] = bool[kMaxTexUnits](...);
+ addShaderBoolTexArray(outStream, "point_sprite_coord_replace",
+ mShaderState.pointSpriteCoordReplaces);
+
+ // bool clip_plane_enables[kMaxClipPlanes] = bool[kMaxClipPlanes](...);
+ addShaderBoolClipPlaneArray(outStream, "clip_plane_enables", mShaderState.clipPlaneEnables);
+
+ // int texture_format[kMaxTexUnits] = int[kMaxTexUnits](...);
+ addShaderIntTexArray(outStream, "texture_env_mode", mShaderState.texEnvModes);
+
+ // int combine_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "combine_rgb", mShaderState.texCombineRgbs);
+
+ // int combine_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "combine_alpha", mShaderState.texCombineAlphas);
+
+ // int src0_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src0_rgb", mShaderState.texCombineSrc0Rgbs);
+
+ // int src0_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src0_alpha", mShaderState.texCombineSrc0Alphas);
+
+ // int src1_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src1_rgb", mShaderState.texCombineSrc1Rgbs);
+
+ // int src1_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src1_alpha", mShaderState.texCombineSrc1Alphas);
+
+ // int src2_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src2_rgb", mShaderState.texCombineSrc2Rgbs);
+
+ // int src2_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "src2_alpha", mShaderState.texCombineSrc2Alphas);
+
+ // int op0_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op0_rgb", mShaderState.texCombineOp0Rgbs);
+
+ // int op0_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op0_alpha", mShaderState.texCombineOp0Alphas);
+
+ // int op1_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op1_rgb", mShaderState.texCombineOp1Rgbs);
+
+ // int op1_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op1_alpha", mShaderState.texCombineOp1Alphas);
+
+ // int op2_rgb[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op2_rgb", mShaderState.texCombineOp2Rgbs);
+
+ // int op2_alpha[kMaxTexUnits];
+ addShaderIntTexArray(outStream, "op2_alpha", mShaderState.texCombineOp2Alphas);
+
+ // int alpha_func;
+ addShaderInt(outStream, "alpha_func", ToGLenum(mShaderState.alphaTestFunc));
+
+ // int fog_mode;
+ addShaderInt(outStream, "fog_mode", ToGLenum(mShaderState.fogMode));
+}
+
+angle::Result GLES1Renderer::initializeRendererProgram(Context *context, State *glState)
+{
+ // See if we have the shader for this combination of states
+ if (mUberShaderState.find(mShaderState) != mUberShaderState.end())
+ {
+ Program *programObject = getProgram(getUberShaderState().programState.program);
+
+ // If this is different than the current program, we need to sync everything
+ // TODO: This could be optimized to only dirty state that differs between the two programs
+ if (glState->getProgram()->id() != programObject->id())
+ {
+ glState->gles1().setAllDirty();
+ }
+
+ ANGLE_TRY(glState->setProgram(context, programObject));
+ return angle::Result::Continue;
+ }
+
+ if (!mRendererProgramInitialized)
+ {
+ mShaderPrograms = new ShaderProgramManager();
+ }
+
+ // If we get here, we don't have a shader for this state, need to create it
+ GLES1ProgramState &programState = mUberShaderState[mShaderState].programState;
+
+ ShaderProgramID vertexShader;
+ ShaderProgramID fragmentShader;
+
+ std::stringstream GLES1DrawVShaderStateDefs;
+ addVertexShaderDefs(GLES1DrawVShaderStateDefs);
+
+ std::stringstream vertexStream;
+ vertexStream << kGLES1DrawVShaderHeader;
+ vertexStream << GLES1DrawVShaderStateDefs.str();
+ vertexStream << kGLES1DrawVShader;
+
+ ANGLE_TRY(
+ compileShader(context, ShaderType::Vertex, vertexStream.str().c_str(), &vertexShader));
+
+ std::stringstream GLES1DrawFShaderStateDefs;
+ addFragmentShaderDefs(GLES1DrawFShaderStateDefs);
+
+ std::stringstream fragmentStream;
+ fragmentStream << kGLES1DrawFShaderVersion;
+ if (mShaderState.mGLES1StateEnabled[GLES1StateEnables::LogicOpThroughFramebufferFetch])
+ {
+ if (context->getExtensions().shaderFramebufferFetchEXT)
+ {
+ fragmentStream << "#extension GL_EXT_shader_framebuffer_fetch : require\n";
+ }
+ else
+ {
+ fragmentStream << "#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require\n";
+ }
+ }
+ fragmentStream << kGLES1DrawFShaderHeader;
+ fragmentStream << GLES1DrawFShaderStateDefs.str();
+ fragmentStream << kGLES1DrawFShaderUniformDefs;
+ if (mShaderState.mGLES1StateEnabled[GLES1StateEnables::LogicOpThroughFramebufferFetch])
+ {
+ if (context->getExtensions().shaderFramebufferFetchEXT)
+ {
+ fragmentStream << kGLES1DrawFShaderFramebufferFetchOutputDef;
+ }
+ else
+ {
+ fragmentStream << kGLES1DrawFShaderFramebufferFetchNonCoherentOutputDef;
+ }
+ fragmentStream << kGLES1DrawFShaderLogicOpFramebufferFetchEnabled;
+ }
+ else
+ {
+ fragmentStream << kGLES1DrawFShaderOutputDef;
+ fragmentStream << kGLES1DrawFShaderLogicOpFramebufferFetchDisabled;
+ }
+ fragmentStream << kGLES1DrawFShaderFunctions;
+ fragmentStream << kGLES1DrawFShaderMultitexturing;
+ fragmentStream << kGLES1DrawFShaderMain;
+
+ ANGLE_TRY(compileShader(context, ShaderType::Fragment, fragmentStream.str().c_str(),
+ &fragmentShader));
+
+ angle::HashMap<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,
+ &programState.program));
+
+ mShaderPrograms->deleteShader(context, vertexShader);
+ mShaderPrograms->deleteShader(context, fragmentShader);
+
+ Program *programObject = getProgram(programState.program);
+
+ programState.projMatrixLoc = programObject->getUniformLocation("projection");
+ programState.modelviewMatrixLoc = programObject->getUniformLocation("modelview");
+ programState.textureMatrixLoc = programObject->getUniformLocation("texture_matrix");
+ programState.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;
+
+ programState.tex2DSamplerLocs[i] = programObject->getUniformLocation(ss2d.str().c_str());
+ programState.texCubeSamplerLocs[i] =
+ programObject->getUniformLocation(sscube.str().c_str());
+ }
+
+ programState.textureEnvColorLoc = programObject->getUniformLocation("texture_env_color");
+ programState.rgbScaleLoc = programObject->getUniformLocation("texture_env_rgb_scale");
+ programState.alphaScaleLoc = programObject->getUniformLocation("texture_env_alpha_scale");
+
+ programState.alphaTestRefLoc = programObject->getUniformLocation("alpha_test_ref");
+
+ programState.materialAmbientLoc = programObject->getUniformLocation("material_ambient");
+ programState.materialDiffuseLoc = programObject->getUniformLocation("material_diffuse");
+ programState.materialSpecularLoc = programObject->getUniformLocation("material_specular");
+ programState.materialEmissiveLoc = programObject->getUniformLocation("material_emissive");
+ programState.materialSpecularExponentLoc =
+ programObject->getUniformLocation("material_specular_exponent");
+
+ programState.lightModelSceneAmbientLoc =
+ programObject->getUniformLocation("light_model_scene_ambient");
+
+ programState.lightAmbientsLoc = programObject->getUniformLocation("light_ambients");
+ programState.lightDiffusesLoc = programObject->getUniformLocation("light_diffuses");
+ programState.lightSpecularsLoc = programObject->getUniformLocation("light_speculars");
+ programState.lightPositionsLoc = programObject->getUniformLocation("light_positions");
+ programState.lightDirectionsLoc = programObject->getUniformLocation("light_directions");
+ programState.lightSpotlightExponentsLoc =
+ programObject->getUniformLocation("light_spotlight_exponents");
+ programState.lightSpotlightCutoffAnglesLoc =
+ programObject->getUniformLocation("light_spotlight_cutoff_angles");
+ programState.lightAttenuationConstsLoc =
+ programObject->getUniformLocation("light_attenuation_consts");
+ programState.lightAttenuationLinearsLoc =
+ programObject->getUniformLocation("light_attenuation_linears");
+ programState.lightAttenuationQuadraticsLoc =
+ programObject->getUniformLocation("light_attenuation_quadratics");
+
+ programState.fogDensityLoc = programObject->getUniformLocation("fog_density");
+ programState.fogStartLoc = programObject->getUniformLocation("fog_start");
+ programState.fogEndLoc = programObject->getUniformLocation("fog_end");
+ programState.fogColorLoc = programObject->getUniformLocation("fog_color");
+
+ programState.clipPlanesLoc = programObject->getUniformLocation("clip_planes");
+
+ programState.logicOpLoc = programObject->getUniformLocation("logic_op");
+
+ programState.pointSizeMinLoc = programObject->getUniformLocation("point_size_min");
+ programState.pointSizeMaxLoc = programObject->getUniformLocation("point_size_max");
+ programState.pointDistanceAttenuationLoc =
+ programObject->getUniformLocation("point_distance_attenuation");
+
+ programState.drawTextureCoordsLoc = programObject->getUniformLocation("draw_texture_coords");
+ programState.drawTextureDimsLoc = programObject->getUniformLocation("draw_texture_dims");
+ programState.drawTextureNormalizedCropRectLoc =
+ programObject->getUniformLocation("draw_texture_normalized_crop_rect");
+
+ ANGLE_TRY(glState->setProgram(context, programObject));
+
+ for (int i = 0; i < kTexUnitCount; i++)
+ {
+ setUniform1i(context, programObject, programState.tex2DSamplerLocs[i], i);
+ setUniform1i(context, programObject, programState.texCubeSamplerLocs[i], i + kTexUnitCount);
+ }
+ glState->setObjectDirty(GL_PROGRAM);
+
+ // We just created a new program, we need to sync everything
+ glState->gles1().setAllDirty();
+
+ mRendererProgramInitialized = true;
+ return angle::Result::Continue;
+}
+
+void GLES1Renderer::setUniform1i(Context *context,
+ Program *programObject,
+ UniformLocation location,
+ GLint value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform1iv(context, location, 1, &value);
+}
+
+void GLES1Renderer::setUniform1ui(Program *programObject, UniformLocation location, GLuint value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform1uiv(location, 1, &value);
+}
+
+void GLES1Renderer::setUniform1iv(Context *context,
+ Program *programObject,
+ UniformLocation location,
+ GLint count,
+ const GLint *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform1iv(context, location, count, value);
+}
+
+void GLES1Renderer::setUniformMatrix4fv(Program *programObject,
+ UniformLocation location,
+ GLint count,
+ GLboolean transpose,
+ const GLfloat *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniformMatrix4fv(location, count, transpose, value);
+}
+
+void GLES1Renderer::setUniform4fv(Program *programObject,
+ UniformLocation location,
+ GLint count,
+ const GLfloat *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform4fv(location, count, value);
+}
+
+void GLES1Renderer::setUniform3fv(Program *programObject,
+ UniformLocation location,
+ GLint count,
+ const GLfloat *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform3fv(location, count, value);
+}
+
+void GLES1Renderer::setUniform2fv(Program *programObject,
+ UniformLocation location,
+ GLint count,
+ const GLfloat *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform2fv(location, count, value);
+}
+
+void GLES1Renderer::setUniform1f(Program *programObject, UniformLocation location, GLfloat value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform1fv(location, 1, &value);
+}
+
+void GLES1Renderer::setUniform1fv(Program *programObject,
+ UniformLocation location,
+ GLint count,
+ const GLfloat *value)
+{
+ if (location.value == -1)
+ return;
+ programObject->setUniform1fv(location, 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