text: /* libs/pixelflinger/codeflinger/GGLAssembler.h
  **
  ** Copyright 2006, 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.
  */
  
  
  #ifndef ANDROID_GGLASSEMBLER_H
  #define ANDROID_GGLASSEMBLER_H
  
  #include <stdint.h>
  #include <sys/types.h>
  
  #include <private/pixelflinger/ggl_context.h>
  
  #include "codeflinger/ARMAssemblerProxy.h"
  
  
  namespace android {
  
  // ----------------------------------------------------------------------------
  
  #define CONTEXT_LOAD(REG, FIELD) \
      LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
  
  #define CONTEXT_STORE(REG, FIELD) \
      STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
  
  
  class RegisterAllocator
  {
  public:
      class RegisterFile;
      
      RegisterFile&   registerFile();
      int             reserveReg(int reg);
      int             obtainReg();
      void            recycleReg(int reg);
      void            reset();
  
      class RegisterFile
      {
      public:
                              RegisterFile();
                              RegisterFile(const RegisterFile& rhs);
                              ~RegisterFile();
  
                  void        reset();
  
                  bool operator == (const RegisterFile& rhs) const;
                  bool operator != (const RegisterFile& rhs) const {
                      return !operator == (rhs);
                  }
  
                  int         reserve(int reg);
                  void        reserveSeveral(uint32_t regMask);
  
                  void        recycle(int reg);
                  void        recycleSeveral(uint32_t regMask);
  
                  int         obtain();
          inline  int         isUsed(int reg) const;
  
                  bool        hasFreeRegs() const;
                  int         countFreeRegs() const;                
  
                  uint32_t    touched() const;
          inline  uint32_t    status() const { return mStatus; }
          
          enum {
              OUT_OF_REGISTERS = 0x1
          };
  
      private:
          uint32_t    mRegs;
          uint32_t    mTouched;
          uint32_t    mStatus;
      };
   
      class Scratch
      {
      public:
              Scratch(RegisterFile& regFile)
                  : mRegFile(regFile), mScratch(0) { 
              }
              ~Scratch() {
                  mRegFile.recycleSeveral(mScratch);
              }
          int obtain() { 
              int reg = mRegFile.obtain();
              mScratch |= 1<<reg;
              return reg;
          }
          void recycle(int reg) {
              mRegFile.recycle(reg);
              mScratch &= ~(1<<reg);
          }
          bool isUsed(int reg) {
              return (mScratch & (1<<reg));
          }
          int countFreeRegs() {
              return mRegFile.countFreeRegs();
          }
      private:
          RegisterFile&   mRegFile;
          uint32_t        mScratch;
      };
  
      class Spill
      {
      public:
          Spill(RegisterFile& regFile, ARMAssemblerInterface& gen, uint32_t reglist)
              : mRegFile(regFile), mGen(gen), mRegList(reglist), mCount(0)
          {
              if (reglist) {
                  int count = 0;
                  while (reglist) {
                      count++;
                      reglist &= ~(1 << (31 - __builtin_clz(reglist)));
                  }
                  if (count == 1) {
                      int reg = 31 - __builtin_clz(mRegList);
                      mGen.STR(mGen.AL, reg, mGen.SP, mGen.immed12_pre(-4, 1));
                  } else {
                      mGen.STM(mGen.AL, mGen.DB, mGen.SP, 1, mRegList);
                  }
                  mRegFile.recycleSeveral(mRegList);
                  mCount = count;
              }
          }
          ~Spill() {
              if (mRegList) {
                  if (mCount == 1) {
                      int reg = 31 - __builtin_clz(mRegList);
                      mGen.LDR(mGen.AL, reg, mGen.SP, mGen.immed12_post(4));
                  } else {
                      mGen.LDM(mGen.AL, mGen.IA, mGen.SP, 1, mRegList);
                  }
                  mRegFile.reserveSeveral(mRegList);
              }
          }
      private:
          RegisterFile&           mRegFile;
          ARMAssemblerInterface&  mGen;
          uint32_t                mRegList;
          int                     mCount;
      };
      
  private:
      RegisterFile    mRegs;
  };
  
  // ----------------------------------------------------------------------------
  
  class GGLAssembler : public ARMAssemblerProxy, public RegisterAllocator
  {
  public:
  
                      GGLAssembler(ARMAssemblerInterface* target);
          virtual     ~GGLAssembler();
  
      uint32_t*   base() const { return 0; } // XXX
      uint32_t*   pc() const { return 0; } // XXX
  
      void        reset(int opt_level);
  
      virtual void    prolog();
      virtual void    epilog(uint32_t touched);
  
          // generate scanline code for given needs
      int         scanline(const needs_t& needs, context_t const* c);
      int         scanline_core(const needs_t& needs, context_t const* c);
  
          enum {
              CLEAR_LO    = 0x0001,
              CLEAR_HI    = 0x0002,
              CORRUPTIBLE = 0x0004,
              FIRST       = 0x0008
          };
  
          enum { //load/store flags
              WRITE_BACK  = 0x0001
          };
  
          struct reg_t {
              reg_t() : reg(-1), flags(0) {
              }
              reg_t(int r, int f=0)
                  : reg(r), flags(f) {
              }
              void setTo(int r, int f=0) {
                  reg=r; flags=f;
              }
              int         reg;
              uint16_t    flags;
          };
  
          struct integer_t : public reg_t {
              integer_t() : reg_t(), s(0) {
              }
              integer_t(int r, int sz=32, int f=0)
                  : reg_t(r, f), s(sz) {
              }
              void setTo(int r, int sz=32, int f=0) {
                  reg_t::setTo(r, f); s=sz;
              }
              int8_t s;
              inline int size() const { return s; }
          };
          
          struct pixel_t : public reg_t {
              pixel_t() : reg_t() {
                  memset(&format, 0, sizeof(GGLFormat));
              }
              pixel_t(int r, const GGLFormat* fmt, int f=0)
                  : reg_t(r, f), format(*fmt) {
              }
              void setTo(int r, const GGLFormat* fmt, int f=0) {
                  reg_t::setTo(r, f); format = *fmt;
              }
              GGLFormat format;
              inline int hi(int c) const { return format.c[c].h; }
              inline int low(int c) const { return format.c[c].l; }
              inline int mask(int c) const { return ((1<<size(c))-1) << low(c); }
              inline int size() const { return format.size*8; }
              inline int size(int c) const { return component_size(c); }
              inline int component_size(int c) const { return hi(c) - low(c); }
          };
  
          struct component_t : public reg_t {
              component_t() : reg_t(), h(0), l(0) {
              }
              component_t(int r, int f=0)
                  : reg_t(r, f), h(0), l(0) {
              }
              component_t(int r, int lo, int hi, int f=0)
                  : reg_t(r, f), h(hi), l(lo) {
              }
              explicit component_t(const integer_t& rhs)
                  : reg_t(rhs.reg, rhs.flags), h(rhs.s), l(0) {
              }
              explicit component_t(const pixel_t& rhs, int component) {
                  setTo(  rhs.reg, 
                          rhs.format.c[component].l,
                          rhs.format.c[component].h,
                          rhs.flags|CLEAR_LO|CLEAR_HI);
              }
              void setTo(int r, int lo=0, int hi=0, int f=0) {
                  reg_t::setTo(r, f); h=hi; l=lo;
              }
              int8_t h;
              int8_t l;
              inline int size() const { return h-l; }
          };
  
          struct pointer_t : public reg_t {
              pointer_t() : reg_t(), size(0) {
              }
              pointer_t(int r, int s, int f=0)
                  : reg_t(r, f), size(s) {
              }
              void setTo(int r, int s, int f=0) {
                  reg_t::setTo(r, f); size=s;
              }
              int8_t size;
          };
  
  
  private:
      struct tex_coord_t {
          reg_t       s;
          reg_t       t;
          pointer_t   ptr;
      };
  
      struct fragment_parts_t {
          uint32_t    packed  : 1;
          uint32_t    reload  : 2;
          uint32_t    iterated_packed  : 1;
          pixel_t     iterated;
          pointer_t   cbPtr;
          pointer_t   covPtr;
          reg_t       count;
          reg_t       argb[4];
          reg_t       argb_dx[4];
          reg_t       z;
          reg_t       dither;
          pixel_t     texel[GGL_TEXTURE_UNIT_COUNT];
          tex_coord_t coords[GGL_TEXTURE_UNIT_COUNT];
      };
      
      struct texture_unit_t {
          int         format_idx;
          GGLFormat   format;
          int         bits;
          int         swrap;
          int         twrap;
          int         env;
          int         pot;
          int         linear;
          uint8_t     mask;
          uint8_t     replaced;
      };
  
      struct texture_machine_t {
          texture_unit_t  tmu[GGL_TEXTURE_UNIT_COUNT];
          uint8_t         mask;
          uint8_t         replaced;
          uint8_t         directTexture;
          uint8_t         activeUnits;
      };
  
      struct component_info_t {
          bool    masked      : 1;
          bool    inDest      : 1;
          bool    needed      : 1;
          bool    replaced    : 1;
          bool    iterated    : 1;
          bool    smooth      : 1;
          bool    blend       : 1;
          bool    fog         : 1;
      };
  
      struct builder_context_t {
          context_t const*    c;
          needs_t             needs;
          int                 Rctx;
      };
  
      template <typename T>
      void modify(T& r, Scratch& regs)
      {
          if (!(r.flags & CORRUPTIBLE)) {
              r.reg = regs.obtain();
              r.flags |= CORRUPTIBLE;
          }
      }
  
      // helpers
      void    base_offset(const pointer_t& d, const pointer_t& b, const reg_t& o);
  
      // texture environement
      void    modulate(   component_t& dest,
                          const component_t& incoming,
                          const pixel_t& texel, int component);
  
      void    decal(  component_t& dest,
                      const component_t& incoming,
                      const pixel_t& texel, int component);
  
      void    blend(  component_t& dest,
                      const component_t& incoming,
                      const pixel_t& texel, int component, int tmu);
  
      void    add(  component_t& dest,
                      const component_t& incoming,
                      const pixel_t& texel, int component);
  
      // load/store stuff
      void    store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
      void    load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
      void    extract(integer_t& d, const pixel_t& s, int component);    
      void    extract(component_t& d, const pixel_t& s, int component);    
      void    extract(integer_t& d, int s, int h, int l, int bits=32);
      void    expand(integer_t& d, const integer_t& s, int dbits);
      void    expand(integer_t& d, const component_t& s, int dbits);
      void    expand(component_t& d, const component_t& s, int dbits);
      void    downshift(pixel_t& d, int component, component_t s, const reg_t& dither);
  
  
      void    mul_factor( component_t& d,
                          const integer_t& v,
                          const integer_t& f);
  
      void    mul_factor_add( component_t& d,
                              const integer_t& v,
                              const integer_t& f,
                              const component_t& a);
  
      void    component_add(  component_t& d,
                              const integer_t& dst,
                              const integer_t& src);
  
      void    component_sat(  const component_t& v);
  
  
      void    build_scanline_prolog(  fragment_parts_t& parts,
                                      const needs_t& needs);
  
      void    build_smooth_shade(const fragment_parts_t& parts);
  
      void    build_component(    pixel_t& pixel,
                                  const fragment_parts_t& parts,
                                  int component,
                                  Scratch& global_scratches);
                                  
      void    build_incoming_component(
                                  component_t& temp,
                                  int dst_size,
                                  const fragment_parts_t& parts,
                                  int component,
                                  Scratch& scratches,
                                  Scratch& global_scratches);
  
      void    init_iterated_color(fragment_parts_t& parts, const reg_t& x);
  
      void    build_iterated_color(   component_t& fragment,
                                      const fragment_parts_t& parts,
                                      int component,
                                      Scratch& regs);
  
      void    decodeLogicOpNeeds(const needs_t& needs);
      
      void    decodeTMUNeeds(const needs_t& needs, context_t const* c);
  
      void    init_textures(  tex_coord_t* coords,
                              const reg_t& x,
                              const reg_t& y);
  
      void    build_textures( fragment_parts_t& parts,
                              Scratch& regs);
  
      void    filter8(   const fragment_parts_t& parts,
                          pixel_t& texel, const texture_unit_t& tmu,
                          int U, int V, pointer_t& txPtr,
                          int FRAC_BITS);
  
      void    filter16(   const fragment_parts_t& parts,
                          pixel_t& texel, const texture_unit_t& tmu,
                          int U, int V, pointer_t& txPtr,
                          int FRAC_BITS);
  
      void    filter24(   const fragment_parts_t& parts,
                          pixel_t& texel, const texture_unit_t& tmu,
                          int U, int V, pointer_t& txPtr,
                          int FRAC_BITS);
  
      void    filter32(   const fragment_parts_t& parts,
                          pixel_t& texel, const texture_unit_t& tmu,
                          int U, int V, pointer_t& txPtr,
                          int FRAC_BITS);
  
      void    build_texture_environment(  component_t& fragment,
                                          const fragment_parts_t& parts,
                                          int component,
                                          Scratch& regs);
  
      void    wrapping(   int d,
                          int coord, int size,
                          int tx_wrap, int tx_linear);
  
      void    build_fog(  component_t& temp,
                          int component,
                          Scratch& parent_scratches);
  
      void    build_blending(     component_t& in_out,
                                  const pixel_t& pixel,
                                  int component,
                                  Scratch& parent_scratches);
  
      void    build_blend_factor(
                  integer_t& factor, int f, int component,
                  const pixel_t& dst_pixel,
                  integer_t& fragment,
                  integer_t& fb,
                  Scratch& scratches);
  
      void    build_blendFOneMinusF(  component_t& temp,
                                      const integer_t& factor, 
                                      const integer_t& fragment,
                                      const integer_t& fb);
  
      void    build_blendOneMinusFF(  component_t& temp,
                                      const integer_t& factor, 
                                      const integer_t& fragment,
                                      const integer_t& fb);
  
      void build_coverage_application(component_t& fragment,
                                      const fragment_parts_t& parts,
                                      Scratch& regs);
  
      void build_alpha_test(component_t& fragment, const fragment_parts_t& parts);
  
      enum { Z_TEST=1, Z_WRITE=2 }; 
      void build_depth_test(const fragment_parts_t& parts, uint32_t mask);
      void build_iterate_z(const fragment_parts_t& parts);
      void build_iterate_f(const fragment_parts_t& parts);
      void build_iterate_texture_coordinates(const fragment_parts_t& parts);
  
      void build_logic_op(pixel_t& pixel, Scratch& regs);
  
      void build_masking(pixel_t& pixel, Scratch& regs);
  
      void build_and_immediate(int d, int s, uint32_t mask, int bits);
  
      bool    isAlphaSourceNeeded() const;
  
      enum {
          FACTOR_SRC=1, FACTOR_DST=2, BLEND_SRC=4, BLEND_DST=8 
      };
      
      enum {
          LOGIC_OP=1, LOGIC_OP_SRC=2, LOGIC_OP_DST=4
      };
  
      static int blending_codes(int fs, int fd);
  
      builder_context_t   mBuilderContext;
      texture_machine_t   mTextureMachine;
      component_info_t    mInfo[4];
      int                 mBlending;
      int                 mMasking;
      int                 mAllMasked;
      int                 mLogicOp;
      int                 mAlphaTest;
      int                 mAA;
      int                 mDithering;
      int                 mDepthTest;
  
      int             mSmooth;
      int             mFog;
      pixel_t         mDstPixel;
      
      GGLFormat       mCbFormat;
      
      int             mBlendFactorCached;
      integer_t       mAlphaSource;
      
      int             mBaseRegister;
      
      int             mBlendSrc;
      int             mBlendDst;
      int             mBlendSrcA;
      int             mBlendDstA;
      
      int             mOptLevel;
  };
  
  // ----------------------------------------------------------------------------
  
  }; // namespace android
  
  #endif // ANDROID_GGLASSEMBLER_H
  