13f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian/* 23f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Copyright 2013 The Android Open Source Project 33f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 43f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License"); 53f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * you may not use this file except in compliance with the License. 63f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * You may obtain a copy of the License at 73f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 83f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * http://www.apache.org/licenses/LICENSE-2.0 93f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Unless required by applicable law or agreed to in writing, software 113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS, 123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * See the License for the specific language governing permissions and 143f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * limitations under the License. 153f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian */ 163f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 173f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H 183f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#define SF_RENDER_ENGINE_PROGRAMCACHE_H 193f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 203f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <GLES2/gl2.h> 213f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 223f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <utils/KeyedVector.h> 23b027f805c9a18893556353f44008683e20ebe049Chia-I Wu#include <utils/Singleton.h> 243f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <utils/TypeHelpers.h> 253f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 263f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include "Description.h" 273f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 283f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopiannamespace android { 293f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 303f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass Description; 312542cb07773302b01b1c22ac7819bf05616c7767Peiyong Linclass Formatter; 323f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass Program; 333f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass String8; 343f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 353f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian/* 363f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * This class generates GLSL programs suitable to handle a given 373f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Description. It's responsible for figuring out what to 383f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * generate from a Description. 393f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * It also maintains a cache of these Programs. 403f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian */ 413f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass ProgramCache : public Singleton<ProgramCache> { 423f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianpublic: 433f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian /* 443f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Key is used to retrieve a Program in the cache. 453f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * A Key is generated from a Description. 463f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian */ 473f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian class Key { 483f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend class ProgramCache; 493f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian typedef uint32_t key_t; 503f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian key_t mKey; 51b027f805c9a18893556353f44008683e20ebe049Chia-I Wu 523f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian public: 533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian enum { 547e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu BLEND_SHIFT = 0, 557e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu BLEND_MASK = 1 << BLEND_SHIFT, 567e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu BLEND_PREMULT = 1 << BLEND_SHIFT, 577e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu BLEND_NORMAL = 0 << BLEND_SHIFT, 587e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 597e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OPACITY_SHIFT = 1, 607e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OPACITY_MASK = 1 << OPACITY_SHIFT, 617e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OPACITY_OPAQUE = 1 << OPACITY_SHIFT, 627e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT, 637e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 647e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu ALPHA_SHIFT = 2, 657e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu ALPHA_MASK = 1 << ALPHA_SHIFT, 667e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu ALPHA_LT_ONE = 1 << ALPHA_SHIFT, 677e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu ALPHA_EQ_ONE = 0 << ALPHA_SHIFT, 687e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 697e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu TEXTURE_SHIFT = 3, 707e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu TEXTURE_MASK = 3 << TEXTURE_SHIFT, 717e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu TEXTURE_OFF = 0 << TEXTURE_SHIFT, 727e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu TEXTURE_EXT = 1 << TEXTURE_SHIFT, 737e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu TEXTURE_2D = 2 << TEXTURE_SHIFT, 747e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 75a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin INPUT_TRANSFORM_MATRIX_SHIFT = 5, 76a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, 77a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT, 78a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, 797e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 80a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin OUTPUT_TRANSFORM_MATRIX_SHIFT = 6, 81a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, 82a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT, 83a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, 84a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin 85a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin INPUT_TF_SHIFT = 7, 867e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu INPUT_TF_MASK = 3 << INPUT_TF_SHIFT, 877e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT, 887e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT, 89131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT, 90a3fb7d6b631c9ecab70ff68443cbdee872ed649fPeiyong Lin INPUT_TF_HLG = 3 << INPUT_TF_SHIFT, 917e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu 92a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin OUTPUT_TF_SHIFT = 9, 937e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT, 947e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT, 957e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT, 96131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT, 97a3fb7d6b631c9ecab70ff68443cbdee872ed649fPeiyong Lin OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT, 98131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu 99a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin Y410_BT2020_SHIFT = 11, 100131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT, 101131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT, 102131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT, 1033f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian }; 1043f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 105b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline Key() : mKey(0) {} 106b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline Key(const Key& rhs) : mKey(rhs.mKey) {} 1073f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1083f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian inline Key& set(key_t mask, key_t value) { 1093f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian mKey = (mKey & ~mask) | value; 1103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return *this; 1113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 113b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; } 114b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); } 115b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; } 116b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; } 117b027f805c9a18893556353f44008683e20ebe049Chia-I Wu inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; } 118a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin inline bool hasInputTransformMatrix() const { 119a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON; 120a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin } 121a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin inline bool hasOutputTransformMatrix() const { 122a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON; 123a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin } 124a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin inline bool hasTransformMatrix() const { 125a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin return hasInputTransformMatrix() || hasOutputTransformMatrix(); 126a296b0c232483ff2d80a814a1a39d02397ba559ePeiyong Lin } 1277e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu inline int getInputTF() const { return (mKey & INPUT_TF_MASK); } 1287e65bc00e46fbae2820fa52c997d72ab69ecd916Chia-I Wu inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); } 12953f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin 13053f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // When HDR and non-HDR contents are mixed, or different types of HDR contents are 13153f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // mixed, we will do a tone mapping process to tone map the input content to output 13253f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // content. Currently, the following conversions handled, they are: 13353f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // * SDR -> HLG 13453f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // * SDR -> PQ 13553f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // * HLG -> PQ 13653f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin inline bool needsToneMapping() const { 13753f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin int inputTF = getInputTF(); 13853f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin int outputTF = getOutputTF(); 13953f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin 14053f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // Return false when converting from SDR to SDR. 14153f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) { 14253f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin return false; 14353f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin } 14453f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) { 14553f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin return false; 14653f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin } 14753f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin 14853f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin inputTF >>= Key::INPUT_TF_SHIFT; 14953f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin outputTF >>= Key::OUTPUT_TF_SHIFT; 15053f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin return inputTF != outputTF; 15153f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin } 152131d3760a0437fac08ff4cc384640b7ca1802d17Chia-I Wu inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; } 1533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1543f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // this is the definition of a friend function -- not a method of class Needs 1553f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { 15688d37ddac876c75dd5d2e39d33787dbcbf833641Romain Guy return (lhs.mKey < rhs.mKey) ? 1 : 0; 1573f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1583f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian }; 1593f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1603f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian ProgramCache(); 1613f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian ~ProgramCache(); 1623f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 16393e14df5b3e0a593c033715b64c8243c578ceb83Chia-I Wu // Generate shaders to populate the cache 16493e14df5b3e0a593c033715b64c8243c578ceb83Chia-I Wu void primeCache(bool hasWideColor); 16593e14df5b3e0a593c033715b64c8243c578ceb83Chia-I Wu 1663f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // useProgram lookup a suitable program in the cache or generates one 1673f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // if none can be found. 1683f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian void useProgram(const Description& description); 1693f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1703f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianprivate: 1713f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // compute a cache Key from a Description 1723f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian static Key computeKey(const Description& description); 1732542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin // Generate EOTF based from Key. 1742542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin static void generateEOTF(Formatter& fs, const Key& needs); 17553f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin // Generate necessary tone mapping methods for OOTF. 17653f320ea3541f43e11768eea122021ce6271cb17Peiyong Lin static void generateToneMappingProcess(Formatter& fs, const Key& needs); 1772542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin // Generate OOTF based from Key. 1782542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin static void generateOOTF(Formatter& fs, const Key& needs); 1792542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin // Generate OETF based from Key. 1802542cb07773302b01b1c22ac7819bf05616c7767Peiyong Lin static void generateOETF(Formatter& fs, const Key& needs); 1813f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // generates a program from the Key 1823f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian static Program* generateProgram(const Key& needs); 1833f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // generates the vertex shader from the Key 1843f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian static String8 generateVertexShader(const Key& needs); 1853f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // generates the fragment shader from the Key 1863f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian static String8 generateFragmentShader(const Key& needs); 1873f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1883f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // Key/Value map used for caching Programs. Currently the cache 1893f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // is never shrunk. 1903f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian DefaultKeyedVector<Key, Program*> mCache; 1913f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}; 1923f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1933f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key) 1943f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1953f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} /* namespace android */ 1963f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1973f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */ 198