You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
572 lines
18 KiB
572 lines
18 KiB
/* 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
|
|
|