📄 scanline.cpp
字号:
/* libs/pixelflinger/scanline.cpp**** 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.*/#define LOG_TAG "pixelflinger"#include <assert.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <cutils/memory.h>#include <cutils/log.h>#include "buffer.h"#include "scanline.h"#include "codeflinger/CodeCache.h"#include "codeflinger/GGLAssembler.h"#include "codeflinger/ARMAssembler.h"//#include "codeflinger/ARMAssemblerOptimizer.h"// ----------------------------------------------------------------------------#define ANDROID_CODEGEN_GENERIC 0 // force generic pixel pipeline#define ANDROID_CODEGEN_C 1 // hand-written C, fallback generic #define ANDROID_CODEGEN_ASM 2 // hand-written asm, fallback generic#define ANDROID_CODEGEN_GENERATED 3 // hand-written asm, fallback codegen#ifdef NDEBUG# define ANDROID_RELEASE# define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED#else# define ANDROID_DEBUG# define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED#endif#if defined(__arm__)# define ANDROID_ARM_CODEGEN 1#else# define ANDROID_ARM_CODEGEN 0#endif#define DEBUG__CODEGEN_ONLY 0// ----------------------------------------------------------------------------namespace android {// ----------------------------------------------------------------------------static void init_y(context_t*, int32_t);static void init_y_noop(context_t*, int32_t);static void init_y_packed(context_t*, int32_t);static void init_y_error(context_t*, int32_t);static void step_y__generic(context_t* c);static void step_y__nop(context_t*);static void step_y__smooth(context_t* c);static void step_y__tmu(context_t* c);static void step_y__w(context_t* c);static void scanline(context_t* c);static void scanline_perspective(context_t* c);static void scanline_perspective_single(context_t* c);static void scanline_t32cb16blend(context_t* c);static void scanline_t32cb16(context_t* c);static void scanline_memcpy(context_t* c);static void scanline_memset8(context_t* c);static void scanline_memset16(context_t* c);static void scanline_memset32(context_t* c);static void scanline_noop(context_t* c);static void scanline_set(context_t* c);static void scanline_clear(context_t* c);static void rect_generic(context_t* c, size_t yc);static void rect_memcpy(context_t* c, size_t yc);extern "C" void scanline_t32cb16blend_arm(uint16_t*, uint32_t*, size_t);extern "C" void scanline_t32cb16_arm(uint16_t *dst, uint32_t *src, size_t ct);// ----------------------------------------------------------------------------struct shortcut_t { needs_filter_t filter; const char* desc; void (*scanline)(context_t*); void (*init_y)(context_t*, int32_t);};// Keep in sync with needsstatic shortcut_t shortcuts[] = { { { { 0x03515104, 0x00000077, { 0x00000A01, 0x00000000 } }, { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } }, "565 fb, 8888 tx, blend", scanline_t32cb16blend, init_y_noop }, { { { 0x03010104, 0x00000077, { 0x00000A01, 0x00000000 } }, { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } }, "565 fb, 8888 tx", scanline_t32cb16, init_y_noop }, { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } }, { 0x00000000, 0x00000007, { 0x00000000, 0x00000000 } } }, "(nop) alpha test", scanline_noop, init_y_noop }, { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } }, { 0x00000000, 0x00000070, { 0x00000000, 0x00000000 } } }, "(nop) depth test", scanline_noop, init_y_noop }, { { { 0x05000000, 0x00000000, { 0x00000000, 0x00000000 } }, { 0x0F000000, 0x00000080, { 0x00000000, 0x00000000 } } }, "(nop) logic_op", scanline_noop, init_y_noop }, { { { 0xF0000000, 0x00000000, { 0x00000000, 0x00000000 } }, { 0xF0000000, 0x00000080, { 0x00000000, 0x00000000 } } }, "(nop) color mask", scanline_noop, init_y_noop }, { { { 0x0F000000, 0x00000077, { 0x00000000, 0x00000000 } }, { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } }, "(set) logic_op", scanline_set, init_y_noop }, { { { 0x00000000, 0x00000077, { 0x00000000, 0x00000000 } }, { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } }, "(clear) logic_op", scanline_clear, init_y_noop }, { { { 0x03000000, 0x00000077, { 0x00000000, 0x00000000 } }, { 0xFFFFFF00, 0x000000F7, { 0x00000000, 0x00000000 } } }, "(clear) blending 0/0", scanline_clear, init_y_noop }, { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } }, { 0x0000003F, 0x00000000, { 0x00000000, 0x00000000 } } }, "(error) invalid color-buffer format", scanline_noop, init_y_error },};static const needs_filter_t noblend1to1 = { // (disregard dithering, see below) { 0x03010100, 0x00000077, { 0x00000A00, 0x00000000 } }, { 0xFFFFFFC0, 0xFFFFFEFF, { 0xFFFFFFC0, 0x0000003F } }};static const needs_filter_t fill16noblend = { { 0x03010100, 0x00000077, { 0x00000000, 0x00000000 } }, { 0xFFFFFFC0, 0xFFFFFFFF, { 0x0000003F, 0x0000003F } }};// ----------------------------------------------------------------------------#if ANDROID_ARM_CODEGENstatic CodeCache gCodeCache(12 * 1024);class ScanlineAssembly : public Assembly { AssemblyKey<needs_t> mKey;public: ScanlineAssembly(needs_t needs, size_t size) : Assembly(size), mKey(needs) { } const AssemblyKey<needs_t>& key() const { return mKey; }};#endif// ----------------------------------------------------------------------------void ggl_init_scanline(context_t* c){ c->init_y = init_y; c->step_y = step_y__generic; c->scanline = scanline;}void ggl_uninit_scanline(context_t* c){ if (c->state.buffers.coverage) free(c->state.buffers.coverage);#if ANDROID_ARM_CODEGEN if (c->scanline_as) c->scanline_as->decStrong(c);#endif}// ----------------------------------------------------------------------------static void pick_scanline(context_t* c){#if (!defined(DEBUG__CODEGEN_ONLY) || (DEBUG__CODEGEN_ONLY == 0))#if ANDROID_CODEGEN == ANDROID_CODEGEN_GENERIC c->init_y = init_y; c->step_y = step_y__generic; c->scanline = scanline; return;#endif //printf("*** needs [%08lx:%08lx:%08lx:%08lx]\n", // c->state.needs.n, c->state.needs.p, // c->state.needs.t[0], c->state.needs.t[1]); // first handle the special case that we cannot test with a filter const uint32_t cb_format = GGL_READ_NEEDS(CB_FORMAT, c->state.needs.n); if (GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0]) == cb_format) { if (c->state.needs.match(noblend1to1)) { // this will match regardless of dithering state, since both // src and dest have the same format anyway, there is no dithering // to be done. const GGLFormat* f = &(c->formats[GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0])]); if ((f->components == GGL_RGB) || (f->components == GGL_RGBA) || (f->components == GGL_LUMINANCE) || (f->components == GGL_LUMINANCE_ALPHA)) { // format must have all of RGB components // (so the current color doesn't show through) c->scanline = scanline_memcpy; c->init_y = init_y_noop; return; } } } if (c->state.needs.match(fill16noblend)) { c->init_y = init_y_packed; switch (c->formats[cb_format].size) { case 1: c->scanline = scanline_memset8; return; case 2: c->scanline = scanline_memset16; return; case 4: c->scanline = scanline_memset32; return; } } const int numFilters = sizeof(shortcuts)/sizeof(shortcut_t); for (int i=0 ; i<numFilters ; i++) { if (c->state.needs.match(shortcuts[i].filter)) { c->scanline = shortcuts[i].scanline; c->init_y = shortcuts[i].init_y; return; } }#endif // DEBUG__CODEGEN_ONLY c->init_y = init_y; c->step_y = step_y__generic;#if ANDROID_ARM_CODEGEN // we're going to have to generate some code... // here, generate code for our pixel pipeline const AssemblyKey<needs_t> key(c->state.needs); sp<Assembly> assembly = gCodeCache.lookup(key); if (assembly == 0) { // create a new assembly region sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs, 1024); // initialize our assembler GGLAssembler assembler( new ARMAssembler(a) ); //GGLAssembler assembler( // new ARMAssemblerOptimizer(new ARMAssembler(a)) ); // generate the scanline code for the given needs int err = assembler.scanline(c->state.needs, c); if (ggl_likely(!err)) { // finally, cache this assembly err = gCodeCache.cache(a->key(), a); } if (ggl_unlikely(err)) { LOGE("error generating or caching assembly. Reverting to NOP."); c->scanline = scanline_noop; c->init_y = init_y_noop; c->step_y = step_y__nop; return; } assembly = a; } // release the previous assembly if (c->scanline_as) { c->scanline_as->decStrong(c); } //LOGI("using generated pixel-pipeline"); c->scanline_as = assembly.get(); c->scanline_as->incStrong(c); // hold on to assembly c->scanline = (void(*)(context_t* c))assembly->base();#else// LOGW("using generic (slow) pixel-pipeline"); c->scanline = scanline;#endif}void ggl_pick_scanline(context_t* c){ pick_scanline(c); if ((c->state.enables & GGL_ENABLE_W) && (c->state.enables & GGL_ENABLE_TMUS)) { c->span = c->scanline; c->scanline = scanline_perspective; if (!(c->state.enabled_tmu & (c->state.enabled_tmu - 1))) { // only one TMU enabled c->scanline = scanline_perspective_single; } }}// ----------------------------------------------------------------------------static void blending(context_t* c, pixel_t* fragment, pixel_t* fb);static void blend_factor(context_t* c, pixel_t* r, uint32_t factor, const pixel_t* src, const pixel_t* dst);static void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv);#if ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)// no need to compile the generic-pipeline, it can't be reachedvoid scanline(context_t*){}#elsevoid rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv){ if (su && sv) { if (su > sv) { v = ggl_expand(v, sv, su); sv = su; } else if (su < sv) { u = ggl_expand(u, su, sv); su = sv; } }}void blending(context_t* c, pixel_t* fragment, pixel_t* fb){ rescale(fragment->c[0], fragment->s[0], fb->c[0], fb->s[0]); rescale(fragment->c[1], fragment->s[1], fb->c[1], fb->s[1]); rescale(fragment->c[2], fragment->s[2], fb->c[2], fb->s[2]); rescale(fragment->c[3], fragment->s[3], fb->c[3], fb->s[3]); pixel_t sf, df; blend_factor(c, &sf, c->state.blend.src, fragment, fb); blend_factor(c, &df, c->state.blend.dst, fragment, fb); fragment->c[1] = gglMulAddx(fragment->c[1], sf.c[1], gglMulx(fb->c[1], df.c[1])); fragment->c[2] = gglMulAddx(fragment->c[2], sf.c[2], gglMulx(fb->c[2], df.c[2])); fragment->c[3] = gglMulAddx(fragment->c[3], sf.c[3], gglMulx(fb->c[3], df.c[3])); if (c->state.blend.alpha_separate) { blend_factor(c, &sf, c->state.blend.src_alpha, fragment, fb); blend_factor(c, &df, c->state.blend.dst_alpha, fragment, fb); } fragment->c[0] = gglMulAddx(fragment->c[0], sf.c[0], gglMulx(fb->c[0], df.c[0])); // clamp to 1.0 if (fragment->c[0] >= (1LU<<fragment->s[0])) fragment->c[0] = (1<<fragment->s[0])-1; if (fragment->c[1] >= (1LU<<fragment->s[1])) fragment->c[1] = (1<<fragment->s[1])-1; if (fragment->c[2] >= (1LU<<fragment->s[2])) fragment->c[2] = (1<<fragment->s[2])-1; if (fragment->c[3] >= (1LU<<fragment->s[3])) fragment->c[3] = (1<<fragment->s[3])-1;}static inline int blendfactor(uint32_t x, uint32_t size, uint32_t def = 0){ if (!size) return def; // scale to 16 bits
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -