Edit

kc3-lang/angle/src/libANGLE/GLES1Renderer.cpp

Branch :

  • Show log

    Commit

  • Author : Lubosz Sarnecki
    Date : 2021-05-06 17:06:58
    Hash : e40edf92
    Message : FrameCapture: Add GLES1 support to CaptureVertexArrayData. Implement CaptureVertexPointerES1 that captures specific GLES1 vertex pointer functions depending on the attribute index. Use GLES1 capture functions in CaptureVertexArrayData by detecting the current context version. Implement VertexArrayType function in GLES1Renderer to get a ClientVertexArrayType enum from a vertex attrib index. Bug: angleproject:5893 Change-Id: I442b2e29475ca817860388cafc120db90a0fb9c4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2846838 Reviewed-by: Cody Northrop <cnorthrop@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>

  • src/libANGLE/GLES1Renderer.cpp
  • //
    // 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
    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())
        {
            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,
                                             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;
    }
    
    angle::Result GLES1Renderer::initializeRendererProgram(Context *context, State *glState)
    {
        if (mRendererProgramInitialized)
        {
            return angle::Result::Continue;
        }
    
        mShaderPrograms = new ShaderProgramManager();
    
        ShaderProgramID vertexShader;
        ShaderProgramID 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));
    
        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,
                              &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,
                                     UniformLocation location,
                                     GLint value)
    {
        if (location.value == -1)
            return;
        programObject->setUniform1iv(context, 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