| /* 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 "ARMAssemblerProxy.h" | 
 |  | 
 |  | 
 | namespace android { | 
 |  | 
 | // ---------------------------------------------------------------------------- | 
 |  | 
 | #define CONTEXT_ADDR_LOAD(REG, FIELD) \ | 
 |     ADDR_LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD))) | 
 |  | 
 | #define CONTEXT_ADDR_STORE(REG, FIELD) \ | 
 |     ADDR_STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD))) | 
 |  | 
 | #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; | 
 |      | 
 |                     RegisterAllocator(int arch);  // NOLINT, implicit | 
 |     RegisterFile&   registerFile(); | 
 |     int             reserveReg(int reg); | 
 |     int             obtainReg(); | 
 |     void            recycleReg(int reg); | 
 |     void            reset(); | 
 |  | 
 |     class RegisterFile | 
 |     { | 
 |     public: | 
 |                             RegisterFile(int arch);  // NOLINT, implicit | 
 |                             RegisterFile(const RegisterFile& rhs, int arch); | 
 |                             ~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; | 
 |         int         mArch; | 
 |         uint32_t    mRegisterOffset;    // lets reg alloc use 2..17 for mips | 
 |                                         // while arm uses 0..15 | 
 |     }; | 
 |   | 
 |     class Scratch | 
 |     { | 
 |     public: | 
 |             explicit 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: | 
 |  | 
 |     explicit    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)  // NOLINT, implicit | 
 |                 : 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)  // NOLINT, implicit | 
 |                 : 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)  // NOLINT, implicit | 
 |                 : 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: | 
 |     // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset | 
 |     // methods by providing a reset method with a different parameter set. The | 
 |     // intent of GGLAssembler's reset method is to wrap the inherited reset | 
 |     // methods, so make these methods private in order to prevent direct calls | 
 |     // to these methods from clients. | 
 |     using RegisterAllocator::reset; | 
 |     using ARMAssemblerProxy::reset; | 
 |  | 
 |     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 |