034c475931
* Declare explicit conversion constructors. * Add NOLINT for implicit conversion constructors. * Fix also some misaligned indendations. Bug: 28341362 Change-Id: Idf911f35923b408d92285cc1a053f382ba08c63e Test: build with clang-tidy
572 lines
18 KiB
C++
572 lines
18 KiB
C++
/* 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
|