C++程序  |  614行  |  23.21 KB

/**
 **
 ** Copyright 2010, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 **
 **     http://www.apache.org/licenses/LICENSE-2.0
 **
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "src/pixelflinger2/pixelflinger2.h"
#include "src/pixelflinger2/texture.h"
#include "src/mesa/main/mtypes.h"

#if !USE_LLVM_SCANLINE

static void Saturate(Vec4<BlendComp_t> * color)
{
   color->r = MIN2(MAX2(color->r, 0), 255);
   color->g = MIN2(MAX2(color->g, 0), 255);
   color->b = MIN2(MAX2(color->b, 0), 255);
   color->a = MIN2(MAX2(color->a, 0), 255);
}

static inline void RGBAIntToRGBAIntx4(unsigned rgba, Vec4<BlendComp_t> * color) __attribute__((always_inline));
static inline void RGBAIntToRGBAIntx4(unsigned rgba, Vec4<BlendComp_t> * color)
{
   color->r = rgba & 0xff;
   color->g = (rgba >>= 8) & 0xff;
   color->b = (rgba >>= 8) & 0xff;
   color->a = (rgba >>= 8);
}

static inline void RGBAFloatx4ToRGBAIntx4(Vector4 * v, Vec4<BlendComp_t> * color)
{
   color->r = v->r * 255;
   color->g = v->g * 255;
   color->b = v->b * 255;
   color->a = v->a * 255;
}

static inline unsigned RGBAIntx4ToRGBAInt(const Vec4<BlendComp_t> * color);
static inline unsigned RGBAIntx4ToRGBAInt(const Vec4<BlendComp_t> * color)
{
   return color->r | (color->g << 8) | (color->b << 16) | (color->a << 24);
}



//static inline Pixel Vector4ToPixelRGBA(const Vector4 * color) __attribute__((always_inline));
//static inline Pixel Vector4ToPixelRGBA(const Vector4 * color)
//{
//    Pixel pixel;
//#if defined(__ARM_HAVE_NEON) && USE_NEON
//    int32x4_t  c = vcvtq_s32_f32(vmulq_n_f32(color->f4, 255.0f));
//    c = vminq_s32(c, vdupq_n_s32(255));
//    c = vmaxq_s32(c, vdupq_n_s32(0));
//    pixel.channels[0] = (unsigned char)vgetq_lane_s32(c, 0);
//    pixel.channels[1] = (unsigned char)vgetq_lane_s32(c, 1);
//    pixel.channels[2] = (unsigned char)vgetq_lane_s32(c, 2);
//    pixel.channels[3] = (unsigned char)vgetq_lane_s32(c, 3);
//#else
//    pixel.channels[0] = (unsigned char)MIN2(MAX2((short)(color->r * 255), 0), 255);
//	pixel.channels[1] = (unsigned char)MIN2(MAX2((short)(color->g * 255), 0), 255);
//	pixel.channels[2] = (unsigned char)MIN2(MAX2((short)(color->b * 255), 0), 255);
//	pixel.channels[3] = (unsigned char)MIN2(MAX2((short)(color->a * 255), 0), 255);
//#endif //#if USE_FIXED_POINT
//	return pixel;
//}

template<typename T>
static inline void BlendFactor(const unsigned mode, T & factor, const T & src,
                               const T & dst, const T & constant, const T & one,
                               const T & zero, const BlendComp_t & srcA, const BlendComp_t & dstA,
                               const BlendComp_t & constantA, const BlendComp_t & sOne) __attribute__((always_inline));
template<typename T>
static inline void BlendFactor(const unsigned mode, T & factor, const T & src,
                               const T & dst, const T & constant, const T & one,
                               const T & zero, const BlendComp_t & srcA, const BlendComp_t & dstA,
                               const BlendComp_t & constantA, const BlendComp_t & sOne)
{
   switch (mode) {
   case 0: // GL_ZERO
      factor = zero;
      return;
   case 1: // GL_ONE
      factor = one;
      return;
   case 2: // GL_SRC_COLOR:
      factor = src;
      return;
   case 3: // GL_ONE_MINUS_SRC_COLOR:
      factor = one;
      factor -= src;
      return;
   case 4: // GL_DST_COLOR:
      factor = dst;
      return;
   case 5: // GL_ONE_MINUS_DST_COLOR:
      factor = one;
      factor -= dst;
      return;
   case 6: // GL_SRC_ALPHA:
      factor = srcA;
      return;
   case 7: // GL_ONE_MINUS_SRC_ALPHA:
      factor = sOne - srcA;
      return;
   case 8: // GL_DST_ALPHA:
      factor = dstA;
      return;
   case 9: // GL_ONE_MINUS_DST_ALPHA:
      factor = sOne - dstA;
      return;
   case 10: // GL_SRC_ALPHA_SATURATE: // valid only for source color; src alpha = 1
      factor = MIN2(srcA, sOne - dstA);
      return;
   case 11: // GL_CONSTANT_COLOR:
      factor = constant;
      return;
   case 12: // GL_ONE_MINUS_CONSTANT_COLOR:
      factor = one;
      factor -= constant;
      return;
   case 13: // GL_CONSTANT_ALPHA:
      factor = constantA;
      return;
   case 14: // GL_ONE_MINUS_CONSTANT_ALPHA:
      factor = sOne - constantA;
      return;
   default:
      assert(0);
      return;
   }
}

unsigned char StencilOp(const unsigned op, unsigned char s, const unsigned char ref)
{
   switch (op) {
   case 0: // GL_ZERO
      return 0;
   case 1: // GL_KEEP
      return s;
   case 2: // GL_REPLACE
      return ref;
   case 3: // GL_INCR
      if (s < 255)
         return ++s;
      return s;
   case 4: // GL_DECR
      if (s > 0)
         return --s;
      return 0;
   case 5: // GL_INVERT
      return ~s;
   case 6: // GL_INCR_WRAP
      return ++s;
   case 7: // GL_DECR_WRAP
      return --s;
   default:
      assert(0);
      return s;
   }
}

#endif // #if !USE_LLVM_SCANLINE

#ifdef USE_LLVM_SCANLINE
typedef void (* ScanLineFunction_t)(VertexOutput * start, VertexOutput * step,
                                    const float (*constants)[4], void * frame,
                                    int * depth, unsigned char * stencil,
                                    GGLActiveStencil *, unsigned count);
#endif

void GGLScanLine(const gl_shader_program * program, const GGLPixelFormat colorFormat,
                 void * frameBuffer, int * depthBuffer, unsigned char * stencilBuffer,
                 unsigned bufferWidth, unsigned bufferHeight, GGLActiveStencil * activeStencil,
                 const VertexOutput_t * start, const VertexOutput_t * end, const float (*constants)[4])
{
#if !USE_LLVM_SCANLINE
   assert(!"only for USE_LLVM_SCANLINE");
#endif

//   LOGD("pf2: GGLScanLine program=%p format=0x%.2X frameBuffer=%p depthBuffer=%p stencilBuffer=%p ",
//      program, colorFormat, frameBuffer, depthBuffer, stencilBuffer);

   const unsigned int varyingCount = program->VaryingSlots;
   const unsigned y = start->position.y, startX = start->position.x,
                      endX = end->position.x;

   assert(bufferWidth > startX && bufferWidth > endX);
   assert(bufferHeight > y);

   char * frame = (char *)frameBuffer;
   if (GGL_PIXEL_FORMAT_RGBA_8888 == colorFormat)
      frame += (y * bufferWidth + startX) * 4;
   else if (GGL_PIXEL_FORMAT_RGB_565 == colorFormat)
      frame += (y * bufferWidth + startX) * 2;
   else 
      assert(0);
   const VectorComp_t div = VectorComp_t_CTR(1 / (float)(endX - startX));

   //memcpy(ctx->glCtx->CurrentProgram->ValuesVertexOutput, start, sizeof(*start));
   // shader symbols are mapped to gl_shader_program_Values*
   //VertexOutput & vertex(*(VertexOutput*)ctx->glCtx->CurrentProgram->ValuesVertexOutput);
   VertexOutput vertex(*start);
   VertexOutput vertexDx(*end);

   vertexDx.position -= start->position;
   vertexDx.position *= div;
   //printf("vertexDx.position.z=%.8g \n", vertexDx.position.z);
   for (unsigned i = 0; i < varyingCount; i++) {
      vertexDx.varyings[i] -= start->varyings[i];
      vertexDx.varyings[i] *= div;
   }
   vertexDx.frontFacingPointCoord -= start->frontFacingPointCoord;
   vertexDx.frontFacingPointCoord *= div; // gl_PointCoord, only zw
   vertexDx.frontFacingPointCoord.y = 0; // gl_FrontFacing not interpolated

   int * depth = depthBuffer + y * bufferWidth + startX;
   unsigned char * stencil = stencilBuffer + y * bufferWidth + startX;

   // TODO DXL consider inverting gl_FragCoord.y
   ScanLineFunction_t scanLineFunction = (ScanLineFunction_t)
                                         program->_LinkedShaders[MESA_SHADER_FRAGMENT]->function;
//   LOGD("pf2 GGLScanLine scanline=%p start=%p constants=%p", scanLineFunction, &vertex, constants);
   if (endX >= startX)
      scanLineFunction(&vertex, &vertexDx, constants, frame, depth, stencil, activeStencil, endX - startX + 1);

//   LOGD("pf2: GGLScanLine end");

}

template <bool StencilTest, bool DepthTest, bool DepthWrite, bool BlendEnable>
void ScanLine(const GGLInterface * iface, const VertexOutput * start, const VertexOutput * end)
{
   GGL_GET_CONST_CONTEXT(ctx, iface);
   GGLScanLine(ctx->CurrentProgram, ctx->frameSurface.format, ctx->frameSurface.data,
               (int *)ctx->depthSurface.data, (unsigned char *)ctx->stencilSurface.data,
               ctx->frameSurface.width, ctx->frameSurface.height, &ctx->activeStencil,
               start, end, ctx->CurrentProgram->ValuesUniform);
//   GGL_GET_CONST_CONTEXT(ctx, iface);
//   //    assert((unsigned)start->position.y == (unsigned)end->position.y);
//   //
//   //    assert(GGL_PIXEL_FORMAT_RGBA_8888 == ctx->frameSurface.format);
//   //    assert(GGL_PIXEL_FORMAT_Z_32 == ctx->depthSurface.format);
//   //    assert(ctx->frameSurface.width == ctx->depthSurface.width);
//   //    assert(ctx->frameSurface.height == ctx->depthSurface.height);
//
//   const unsigned int varyingCount = ctx->glCtx->CurrentProgram->VaryingSlots;
//   const unsigned y = start->position.y, startX = start->position.x,
//                      endX = end->position.x;
//
//   //assert(ctx->frameSurface.width > startX && ctx->frameSurface.width > endX);
//   //assert(ctx->frameSurface.height > y);
//
//   unsigned * frame = (unsigned *)ctx->frameSurface.data
//                      + y * ctx->frameSurface.width + startX;
//   const VectorComp_t div = VectorComp_t_CTR(1 / (float)(endX - startX));
//
//   //memcpy(ctx->glCtx->CurrentProgram->ValuesVertexOutput, start, sizeof(*start));
//   // shader symbols are mapped to gl_shader_program_Values*
//   //VertexOutput & vertex(*(VertexOutput*)ctx->glCtx->CurrentProgram->ValuesVertexOutput);
//   VertexOutput vertex(*start);
//   VertexOutput vertexDx(*end);
//
//   vertexDx.position -= start->position;
//   vertexDx.position *= div;
//   //printf("vertexDx.position.z=%.8g \n", vertexDx.position.z);
//   for (unsigned i = 0; i < varyingCount; i++) {
//      vertexDx.varyings[i] -= start->varyings[i];
//      vertexDx.varyings[i] *= div;
//   }
//   vertexDx.frontFacingPointCoord -= start->frontFacingPointCoord;
//   vertexDx.frontFacingPointCoord *= div; // gl_PointCoord, only zw
//   vertexDx.frontFacingPointCoord.y = 0; // gl_FrontFacing not interpolated
//
//#if USE_FORCED_FIXEDPOINT
//   for (unsigned j = 0; j < 4; j++) {
//      for (unsigned i = 0; i < varyingCount; i++) {
//         vertex.varyings[i].i[j] = vertex.varyings[i].f[j] * 65536;
//         vertexDx.varyings[i].i[j] = vertexDx.varyings[i].f[j] * 65536;
//      }
//      vertex.position.i[j] = vertex.position.f[j] * 65536;
//      vertexDx.position.i[j] = vertexDx.position.f[j] * 65536;
//      vertex.frontFacingPointCoord.i[j] = vertex.frontFacingPointCoord.f[j] * 65536;
//   }
//#endif
//
//   int * depth = (int *)ctx->depthSurface.data + y * ctx->frameSurface.width + startX;
//   unsigned char * stencil = (unsigned char *)ctx->stencilSurface.data + y * ctx->frameSurface.width + startX;
//
//#if !USE_LLVM_TEXTURE_SAMPLER
//   extern const GGLContext * textureGGLContext;
//   textureGGLContext = ctx;
//#endif
//
//   // TODO DXL consider inverting gl_FragCoord.y
//
//#if USE_LLVM_SCANLINE
//   ScanLineFunction_t scanLineFunction = (ScanLineFunction_t)
//                                         ctx->glCtx->CurrentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->function;
//   if (endX >= startX) {
//      scanLineFunction(&vertex, &vertexDx, ctx->glCtx->CurrentProgram->ValuesUniform, frame, depth, stencil, &ctx->activeStencil, endX - startX + 1);
//   }
//#else
//
//   int z;
//   bool sCmp = true; // default passed, unless failed by stencil test
//   unsigned char s; // masked stored stencil value
//   const unsigned char sMask = ctx->activeStencil.mask;
//   const unsigned char sRef = ctx->activeStencil.ref;
//   const unsigned sFunc = ctx->activeStencil.face ? 0x200 | ctx->backStencil.func :
//                          0x200 | ctx->frontStencil.func;
//   const unsigned ssFail = ctx->activeStencil.face ? ctx->backStencil.sFail :
//                           ctx->frontStencil.sFail;
//   const unsigned sdFail = ctx->activeStencil.face ? ctx->backStencil.dFail :
//                           ctx->frontStencil.dFail;
//   const unsigned sdPass = ctx->activeStencil.face ? ctx->backStencil.dPass :
//                           ctx->frontStencil.dPass;
//
//   for (unsigned x = startX; x <= endX; x++) {
//      //assert(abs((int)(vertex.position.x) - (int)x) < 2);
//      //assert((unsigned)vertex.position.y == y);
//      if (StencilTest) {
//         s = *stencil & sMask;
//         switch (sFunc) {
//         case GL_NEVER:
//            sCmp = false;
//            break;
//         case GL_LESS:
//            sCmp = sRef < s;
//            break;
//         case GL_EQUAL:
//            sCmp = sRef == s;
//            break;
//         case GL_LEQUAL:
//            sCmp = sRef <= s;
//            break;
//         case GL_GREATER:
//            sCmp = sRef > s;
//            break;
//         case GL_NOTEQUAL:
//            sCmp = sRef != s;
//            break;
//         case GL_GEQUAL:
//            sCmp = sRef >= s;
//            break;
//         case GL_ALWAYS:
//            sCmp = true;
//            break;
//         default:
//            assert(0);
//            break;
//         }
//      }
//
//      if (!StencilTest || sCmp) {
//         z = vertex.position.i[2];
//         if (z & 0x80000000)  // negative float has leading 1
//            z ^= 0x7fffffff;  // bigger negative is smaller
//         bool zCmp = true;
//         if (DepthTest) {
//            switch (0x200 | ctx->state.bufferState.depthFunc) {
//            case GL_NEVER:
//               zCmp = false;
//               break;
//            case GL_LESS:
//               zCmp = z < *depth;
//               break;
//            case GL_EQUAL:
//               zCmp = z == *depth;
//               break;
//            case GL_LEQUAL:
//               zCmp = z <= *depth;
//               break;
//            case GL_GREATER:
//               zCmp = z > *depth;
//               break;
//            case GL_NOTEQUAL:
//               zCmp = z != *depth;
//               break;
//            case GL_GEQUAL:
//               zCmp = z >= *depth;
//               break;
//            case GL_ALWAYS:
//               zCmp = true;
//               break;
//            default:
//               assert(0);
//               break;
//            }
//         }
//         if (!DepthTest || zCmp) {
//            float * varying = (float *)ctx->glCtx->CurrentProgram->ValuesVertexOutput;
//            ShaderFunction_t function = (ShaderFunction_t)ctx->glCtx->CurrentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->function;
//            function(&vertex, &vertex, ctx->glCtx->CurrentProgram->ValuesUniform);
//            //ctx->glCtx->CurrentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->function();
//            if (BlendEnable) {
//               BlendComp_t sOne = 255, sZero = 0;
//               Vec4<BlendComp_t> one = sOne, zero = sZero;
//
//               Vec4<BlendComp_t> src;
////                    if (outputRegDesc.IsInt32Color())
////                        RGBAIntToRGBAIntx4(vertex.fragColor[0].u[0], &src);
////                    else if (outputRegDesc.IsVectorType(Float))
//               RGBAFloatx4ToRGBAIntx4(&vertex.fragColor[0], &src);
////                    else if (outputRegDesc.IsVectorType(Fixed8))
////                    {
////                        src.u[0] = vertex.fragColor[0].u[0];
////                        src.u[1] = vertex.fragColor[0].u[1];
////                        src.u[2] = vertex.fragColor[0].u[2];
////                        src.u[3] = vertex.fragColor[0].u[3];
////                    }
////                    else
////                        assert(0);
//
//               Vec4<BlendComp_t> dst;
//               unsigned dc = *frame;
//               dst.r = dc & 255;
//               dst.g = (dc >>= 8) & 255;
//               dst.b = (dc >>= 8) & 255;
//               dst.a = (dc >>= 8) & 255;
//
//               Vec4<BlendComp_t> sf, df;
//               Vec4<BlendComp_t> blendStateColor(ctx->state.blendState.color[0], ctx->state.blendState.color[1],
//                                                 ctx->state.blendState.color[2], ctx->state.blendState.color[3]);
//
//               BlendFactor(ctx->state.blendState.scf, sf, src, dst,
//                           blendStateColor, one, zero, src.a, dst.a,
//                           blendStateColor.a, sOne);
//               if (ctx->state.blendState.scf != ctx->state.blendState.saf)
//                  BlendFactor(ctx->state.blendState.saf, sf.a, src.a, dst.a,
//                              blendStateColor.a, sOne, sZero, src.a, dst.a,
//                              blendStateColor.a, sOne);
//               BlendFactor(ctx->state.blendState.dcf, df, src, dst,
//                           blendStateColor, one, zero, src.a, dst.a,
//                           blendStateColor.a, sOne);
//               if (ctx->state.blendState.dcf != ctx->state.blendState.daf)
//                  BlendFactor(ctx->state.blendState.daf, df.a, src.a, dst.a,
//                              blendStateColor.a, sOne, sZero, src.a, dst.a,
//                              blendStateColor.a, sOne);
//
//               Vec4<BlendComp_t> sfs(sf), dfs(df);
//               sfs.LShr(7);
//               sf += sfs;
//               dfs.LShr(7);
//               df += dfs;
//
//               src *= sf;
//               dst *= df;
//               Vec4<BlendComp_t> res(src);
//               switch (ctx->state.blendState.ce + GL_FUNC_ADD) {
//               case GL_FUNC_ADD:
//                  res += dst;
//                  break;
//               case GL_FUNC_SUBTRACT:
//                  res -= dst;
//                  break;
//               case GL_FUNC_REVERSE_SUBTRACT:
//                  res = dst;
//                  res -= src;
//                  break;
//               default:
//                  assert(0);
//                  break;
//               }
//               if (ctx->state.blendState.ce != ctx->state.blendState.ae)
//                  switch (ctx->state.blendState.ce + GL_FUNC_ADD) {
//                  case GL_FUNC_ADD:
//                     res.a = src.a + dst.a;
//                     break;
//                  case GL_FUNC_SUBTRACT:
//                     res.a = src.a - dst.a;
//                     break;
//                  case GL_FUNC_REVERSE_SUBTRACT:
//                     res.a = dst.a - src.a;
//                     break;
//                  default:
//                     assert(0);
//                     break;
//                  }
//
//               res.AShr(8);
//               Saturate(&res);
//               *frame = RGBAIntx4ToRGBAInt(&res);
//            } else {
////                    if (outputRegDesc.IsInt32Color())
////                        *frame = vertex.fragColor[0].u[0];
////                    else if (outputRegDesc.IsVectorType(Float))
//               {
//                  Vec4<BlendComp_t> src;
//                  RGBAFloatx4ToRGBAIntx4(&vertex.fragColor[0], &src);
//                  Saturate(&src);
//                  *frame = RGBAIntx4ToRGBAInt(&src);
//               }
////                    else if (outputRegDesc.IsVectorType(Fixed16))
////                    {
////                        Vec4<BlendComp_t> & src = (Vec4<BlendComp_t> &)vertex.fragColor[0];
////                        src.r = (src.r * 255 >> 16);
////                        src.g = (src.g * 255 >> 16);
////                        src.b = (src.b * 255 >> 16);
////                        src.a = (src.a * 255 >> 16);
////                        Saturate(&src);
////                        *frame = RGBAIntx4ToRGBAInt(&src);
////                    }
////                    else if (outputRegDesc.IsVectorType(Fixed8))
////                    {
////                        Vec4<BlendComp_t> & src = (Vec4<BlendComp_t> &)vertex.fragColor[0];
////                        Saturate(&src);
////                        *frame = RGBAIntx4ToRGBAInt(&src);
////                    }
////                    else
////                        assert(0);
//            }
//
//            if (DepthWrite)
//               *depth = z;
//            if (StencilTest)
//               *stencil = StencilOp(sdPass, s, sRef);
//         } else if (StencilTest)
//            *stencil = StencilOp(sdFail, s, sRef);
//      } else if (StencilTest)
//         *stencil = StencilOp(ssFail, s, sRef);
//
//      frame++;
//      depth++;
//      stencil++;
//
//#if USE_FORCED_FIXEDPOINT
//      for (unsigned j = 0; j < 4; j++) {
//         if (ctx->glCtx->Shader.CurrentProgram->FragmentProgram->UsesFragCoord)
//            vertex.position.i[j] += vertexDx.position.i[j];
//         for (unsigned i = 0; i < varyingCount; i++)
//            vertex.varyings[i].i[j] += vertexDx.varyings[i].i[j];
//      }
//      vertex.position.i[2] += vertexDx.position.i[2];
//      if (ctx->glCtx->Shader.CurrentProgram->FragmentProgram->UsesPointCoord) {
//         vertex.frontFacingPointCoord.i[2] = vertexDx.frontFacingPointCoord.i[2];
//         vertex.frontFacingPointCoord.i[3] = vertexDx.frontFacingPointCoord.i[3];
//      }
//#else
//   if (ctx->glCtx->CurrentProgram->UsesFragCoord)
//      vertex.position += vertexDx.position;
//   else if (ctx->state.bufferState.depthTest)
//      vertex.position.z += vertexDx.position.z;
//
//   for (unsigned i = 0; i < varyingCount; i++)
//      vertex.varyings[i] += vertexDx.varyings[i];
//   if (ctx->glCtx->CurrentProgram->UsesPointCoord) {
//      vertex.frontFacingPointCoord.z += vertexDx.frontFacingPointCoord.z;
//      vertex.frontFacingPointCoord.w += vertexDx.frontFacingPointCoord.w;
//   }
//#endif // #if USE_FORCED_FIXEDPOINT
//   }
//
//#endif // #if USE_LLVM_SCANLINE
//
//#if !USE_LLVM_TEXTURE_SAMPLER
//   textureGGLContext = NULL;
//#endif
}

static void PickScanLine(GGLInterface * iface)
{
   GGL_GET_CONTEXT(ctx, iface);

   ctx->interface.ScanLine = NULL;
   if (ctx->state.bufferState.stencilTest) {
      if (ctx->state.bufferState.depthTest) {
         if (ctx->state.blendState.enable)
            ctx->interface.ScanLine = ScanLine<true, true, true, true>;
         else
            ctx->interface.ScanLine = ScanLine<true, true, true, false>;
      } else {
         if (ctx->state.blendState.enable)
            ctx->interface.ScanLine = ScanLine<true, false, false, true>;
         else
            ctx->interface.ScanLine = ScanLine<true, false, false, false>;
      }
   } else {
      if (ctx->state.bufferState.depthTest) {
         if (ctx->state.blendState.enable)
            ctx->interface.ScanLine = ScanLine<false, true, true, true>;
         else
            ctx->interface.ScanLine = ScanLine<false, true, true, false>;
      } else {
         if (ctx->state.blendState.enable)
            ctx->interface.ScanLine = ScanLine<false, false, false, true>;
         else
            ctx->interface.ScanLine = ScanLine<false, false, false, false>;
      }
   }

   assert(ctx->interface.ScanLine);
}

void InitializeScanLineFunctions(GGLInterface * iface)
{
   GGL_GET_CONTEXT(ctx, iface);
   ctx->PickScanLine = PickScanLine;
}