/* * Copyright 2010 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrContext_DEFINED #define GrContext_DEFINED #include "GrClip.h" #include "GrPaint.h" // not strictly needed but requires WK change in LayerTextureUpdaterCanvas to // remove. #include "GrRenderTarget.h" class GrDrawTarget; class GrFontCache; class GrGpu; struct GrGpuStats; class GrIndexBuffer; class GrIndexBufferAllocPool; class GrInOrderDrawBuffer; class GrPathRenderer; class GrPathRendererChain; class GrResourceEntry; class GrResourceCache; class GrStencilBuffer; class GrVertexBuffer; class GrVertexBufferAllocPool; class GR_API GrContext : public GrRefCnt { public: /** * Creates a GrContext from within a 3D context. */ static GrContext* Create(GrEngine engine, GrPlatform3DContext context3D); virtual ~GrContext(); /** * The GrContext normally assumes that no outsider is setting state * within the underlying 3D API's context/device/whatever. This call informs * the context that the state was modified and it should resend. Shouldn't * be called frequently for good performance. */ void resetContext(); /** * Abandons all gpu resources, assumes 3D API state is unknown. Call this * if you have lost the associated GPU context, and thus internal texture, * buffer, etc. references/IDs are now invalid. Should be called even when * GrContext is no longer going to be used for two reasons: * 1) ~GrContext will not try to free the objects in the 3D API. * 2) If you've created GrResources that outlive the GrContext they will * be marked as invalid (GrResource::isValid()) and won't attempt to * free their underlying resource in the 3D API. * Content drawn since the last GrContext::flush() may be lost. */ void contextLost(); /** * Similar to contextLost, but makes no attempt to reset state. * Use this method when GrContext destruction is pending, but * the graphics context is destroyed first. */ void contextDestroyed(); /** * Frees gpu created by the context. Can be called to reduce GPU memory * pressure. */ void freeGpuResources(); /** * Returns the number of bytes of GPU memory hosted by the texture cache. */ size_t getGpuTextureCacheBytes() const; /////////////////////////////////////////////////////////////////////////// // Textures /** * Token that refers to an entry in the texture cache. Returned by * functions that lock textures. Passed to unlockTexture. */ class SK_API TextureCacheEntry { public: TextureCacheEntry() : fEntry(NULL) {} TextureCacheEntry(const TextureCacheEntry& e) : fEntry(e.fEntry) {} TextureCacheEntry& operator= (const TextureCacheEntry& e) { fEntry = e.fEntry; return *this; } GrTexture* texture() const; void reset() { fEntry = NULL; } private: explicit TextureCacheEntry(GrResourceEntry* entry) { fEntry = entry; } void set(GrResourceEntry* entry) { fEntry = entry; } GrResourceEntry* cacheEntry() { return fEntry; } GrResourceEntry* fEntry; friend class GrContext; }; /** * Key generated by client. Should be a unique key on the texture data. * Does not need to consider that width and height of the texture. Two * textures with the same TextureKey but different bounds will not collide. */ typedef uint64_t TextureKey; /** * Create a new entry, based on the specified key and texture, and return * its "locked" entry. Must call be balanced with an unlockTexture() call. * * @param key A client-generated key that identifies the contents * of the texture. Respecified to findAndLockTexture * for subsequent uses of the texture. * @param sampler The sampler state used to draw a texture may be used * to determine how to store the pixel data in the texture * cache. (e.g. different versions may exist for different * wrap modes on GPUs with limited or no NPOT texture * support). Only the wrap and filter fields are used. NULL * implies clamp wrap modes and nearest filtering. * @param desc Description of the texture properties. * @param srcData Pointer to the pixel values. * @param rowBytes The number of bytes between rows of the texture. Zero * implies tightly packed rows. */ TextureCacheEntry createAndLockTexture(TextureKey key, const GrSamplerState* sampler, const GrTextureDesc& desc, void* srcData, size_t rowBytes); /** * Search for an entry based on key and dimensions. If found, "lock" it and * return it. The entry's texture() function will return NULL if not found. * Must be balanced with an unlockTexture() call. * * @param key A client-generated key that identifies the contents * of the texture. * @param width The width of the texture in pixels as specifed in * the GrTextureDesc originally passed to * createAndLockTexture * @param width The height of the texture in pixels as specifed in * the GrTextureDesc originally passed to * createAndLockTexture * @param sampler The sampler state used to draw a texture may be used * to determine the cache entry used. (e.g. different * versions may exist for different wrap modes on GPUs with * limited or no NPOT texture support). Only the wrap and * filter fields are used. NULL implies clamp wrap modes * and nearest filtering. */ TextureCacheEntry findAndLockTexture(TextureKey key, int width, int height, const GrSamplerState* sampler); /** * Determines whether a texture is in the cache. If the texture is found it * will not be locked or returned. This call does not affect the priority of * the texture for deletion. */ bool isTextureInCache(TextureKey key, int width, int height, const GrSamplerState*) const; /** * Enum that determines how closely a returned scratch texture must match * a provided GrTextureDesc. */ enum ScratchTexMatch { /** * Finds a texture that exactly matches the descriptor. */ kExact_ScratchTexMatch, /** * Finds a texture that approximately matches the descriptor. Will be * at least as large in width and height as desc specifies. If desc * specifies that texture is a render target then result will be a * render target. If desc specifies a render target and doesn't set the * no stencil flag then result will have a stencil. Format and aa level * will always match. */ kApprox_ScratchTexMatch }; /** * Returns a texture matching the desc. It's contents are unknown. Subsequent * requests with the same descriptor are not guaranteed to return the same * texture. The same texture is guaranteed not be returned again until it is * unlocked. Must call be balanced with an unlockTexture() call. * * Textures created by createAndLockTexture() hide the complications of * tiling non-power-of-two textures on APIs that don't support this (e.g. * unextended GLES2). Tiling a npot texture created by lockScratchTexture on * such an API will create gaps in the tiling pattern. This includes clamp * mode. (This may be addressed in a future update.) */ TextureCacheEntry lockScratchTexture(const GrTextureDesc& desc, ScratchTexMatch match); /** * When done with an entry, call unlockTexture(entry) on it, which returns * it to the cache, where it may be purged. */ void unlockTexture(TextureCacheEntry entry); /** * Creates a texture that is outside the cache. Does not count against * cache's budget. */ GrTexture* createUncachedTexture(const GrTextureDesc&, void* srcData, size_t rowBytes); /** * Returns true if the specified use of an indexed texture is supported. */ bool supportsIndex8PixelConfig(const GrSamplerState*, int width, int height) const; /** * Return the current texture cache limits. * * @param maxTextures If non-null, returns maximum number of textures that * can be held in the cache. * @param maxTextureBytes If non-null, returns maximum number of bytes of * texture memory that can be held in the cache. */ void getTextureCacheLimits(int* maxTextures, size_t* maxTextureBytes) const; /** * Specify the texture cache limits. If the current cache exceeds either * of these, it will be purged (LRU) to keep the cache within these limits. * * @param maxTextures The maximum number of textures that can be held in * the cache. * @param maxTextureBytes The maximum number of bytes of texture memory * that can be held in the cache. */ void setTextureCacheLimits(int maxTextures, size_t maxTextureBytes); /** * Return the max width or height of a texture supported by the current gpu */ int getMaxTextureSize() const; /** * Return the max width or height of a render target supported by the * current gpu */ int getMaxRenderTargetSize() const; /////////////////////////////////////////////////////////////////////////// // Render targets /** * Sets the render target. * @param target the render target to set. (should not be NULL.) */ void setRenderTarget(GrRenderTarget* target); /** * Gets the current render target. * @return the currently bound render target. Should never be NULL. */ const GrRenderTarget* getRenderTarget() const; GrRenderTarget* getRenderTarget(); /////////////////////////////////////////////////////////////////////////// // Platform Surfaces /** * Wraps an existing texture with a GrTexture object. * * OpenGL: if the object is a texture Gr may change its GL texture params * when it is drawn. * * @param desc description of the object to create. * * @return GrTexture object or NULL on failure. */ GrTexture* createPlatformTexture(const GrPlatformTextureDesc& desc); /** * Wraps an existing render target with a GrRenderTarget object. It is * similar to createPlatformTexture but can be used to draw into surfaces * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that * the client will resolve to a texture). * * @param desc description of the object to create. * * @return GrTexture object or NULL on failure. */ GrRenderTarget* createPlatformRenderTarget( const GrPlatformRenderTargetDesc& desc); /////////////////////////////////////////////////////////////////////////// // Matrix state /** * Gets the current transformation matrix. * @return the current matrix. */ const GrMatrix& getMatrix() const; /** * Sets the transformation matrix. * @param m the matrix to set. */ void setMatrix(const GrMatrix& m); /** * Concats the current matrix. The passed matrix is applied before the * current matrix. * @param m the matrix to concat. */ void concatMatrix(const GrMatrix& m) const; /////////////////////////////////////////////////////////////////////////// // Clip state /** * Gets the current clip. * @return the current clip. */ const GrClip& getClip() const; /** * Sets the clip. * @param clip the clip to set. */ void setClip(const GrClip& clip); /** * Convenience method for setting the clip to a rect. * @param rect the rect to set as the new clip. */ void setClip(const GrIRect& rect); /////////////////////////////////////////////////////////////////////////// // Draws /** * Clear the entire or rect of the render target, ignoring any clips. * @param rect the rect to clear or the whole thing if rect is NULL. * @param color the color to clear to. */ void clear(const GrIRect* rect, GrColor color); /** * Draw everywhere (respecting the clip) with the paint. */ void drawPaint(const GrPaint& paint); /** * Draw the rect using a paint. * @param paint describes how to color pixels. * @param strokeWidth If strokeWidth < 0, then the rect is filled, else * the rect is mitered stroked based on strokeWidth. If * strokeWidth == 0, then the stroke is always a single * pixel thick. * @param matrix Optional matrix applied to the rect. Applied before * context's matrix or the paint's matrix. * The rects coords are used to access the paint (through texture matrix) */ void drawRect(const GrPaint& paint, const GrRect&, GrScalar strokeWidth = -1, const GrMatrix* matrix = NULL); /** * Maps a rect of paint coordinates onto the a rect of destination * coordinates. Each rect can optionally be transformed. The srcRect * is stretched over the dstRect. The dstRect is transformed by the * context's matrix and the srcRect is transformed by the paint's matrix. * Additional optional matrices can be provided by parameters. * * @param paint describes how to color pixels. * @param dstRect the destination rect to draw. * @param srcRect rect of paint coordinates to be mapped onto dstRect * @param dstMatrix Optional matrix to transform dstRect. Applied before * context's matrix. * @param srcMatrix Optional matrix to transform srcRect Applied before * paint's matrix. */ void drawRectToRect(const GrPaint& paint, const GrRect& dstRect, const GrRect& srcRect, const GrMatrix* dstMatrix = NULL, const GrMatrix* srcMatrix = NULL); /** * Draws a path. * * @param paint describes how to color pixels. * @param path the path to draw * @param fill the path filling rule to use. * @param translate optional additional translation applied to the * path. */ void drawPath(const GrPaint& paint, const GrPath& path, GrPathFill fill, const GrPoint* translate = NULL); /** * Draws vertices with a paint. * * @param paint describes how to color pixels. * @param primitiveType primitives type to draw. * @param vertexCount number of vertices. * @param positions array of vertex positions, required. * @param texCoords optional array of texture coordinates used * to access the paint. * @param colors optional array of per-vertex colors, supercedes * the paint's color field. * @param indices optional array of indices. If NULL vertices * are drawn non-indexed. * @param indexCount if indices is non-null then this is the * number of indices. */ void drawVertices(const GrPaint& paint, GrPrimitiveType primitiveType, int vertexCount, const GrPoint positions[], const GrPoint texs[], const GrColor colors[], const uint16_t indices[], int indexCount); /////////////////////////////////////////////////////////////////////////// // Misc. /** * Flags that affect flush() behavior. */ enum FlushBits { /** * A client may want Gr to bind a GrRenderTarget in the 3D API so that * it can be rendered to directly. However, Gr lazily sets state. Simply * calling setRenderTarget() followed by flush() without flags may not * bind the render target. This flag forces the context to bind the last * set render target in the 3D API. */ kForceCurrentRenderTarget_FlushBit = 0x1, /** * A client may reach a point where it has partially rendered a frame * through a GrContext that it knows the user will never see. This flag * causes the flush to skip submission of deferred content to the 3D API * during the flush. */ kDiscard_FlushBit = 0x2, }; /** * Call to ensure all drawing to the context has been issued to the * underlying 3D API. * @param flagsBitfield flags that control the flushing behavior. See * FlushBits. */ void flush(int flagsBitfield = 0); /** * Reads a rectangle of pixels from a render target. * @param target the render target to read from. NULL means the * current render target. * @param left left edge of the rectangle to read (inclusive) * @param top top edge of the rectangle to read (inclusive) * @param width width of rectangle to read in pixels. * @param height height of rectangle to read in pixels. * @param config the pixel config of the destination buffer * @param buffer memory to read the rectangle into. * @param rowBytes number of bytes bewtween consecutive rows. Zero * means rows are tightly packed. * * @return true if the read succeeded, false if not. The read can fail * because of an unsupported pixel config or because no render * target is currently set. */ bool readRenderTargetPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes) { return this->internalReadRenderTargetPixels(target, left, top, width, height, config, buffer, rowBytes, 0); } /** * Copy the src pixels [buffer, rowbytes, pixelconfig] into a render target * at the specified rectangle. * @param target the render target to write into. NULL means the * current render target. * @param left left edge of the rectangle to write (inclusive) * @param top top edge of the rectangle to write (inclusive) * @param width width of rectangle to write in pixels. * @param height height of rectangle to write in pixels. * @param config the pixel config of the source buffer * @param buffer memory to read the rectangle from. * @param rowBytes number of bytes bewtween consecutive rows. Zero * means rows are tightly packed. */ void writeRenderTargetPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes) { this->internalWriteRenderTargetPixels(target, left, top, width, height, config, buffer, rowBytes, 0); } /** * Reads a rectangle of pixels from a texture. * @param texture the texture to read from. * @param left left edge of the rectangle to read (inclusive) * @param top top edge of the rectangle to read (inclusive) * @param width width of rectangle to read in pixels. * @param height height of rectangle to read in pixels. * @param config the pixel config of the destination buffer * @param buffer memory to read the rectangle into. * @param rowBytes number of bytes bewtween consecutive rows. Zero * means rows are tightly packed. * * @return true if the read succeeded, false if not. The read can fail * because of an unsupported pixel config. */ bool readTexturePixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes) { return this->internalReadTexturePixels(texture, left, top, width, height, config, buffer, rowBytes, 0); } /** * Writes a rectangle of pixels to a texture. * @param texture the render target to read from. * @param left left edge of the rectangle to write (inclusive) * @param top top edge of the rectangle to write (inclusive) * @param width width of rectangle to write in pixels. * @param height height of rectangle to write in pixels. * @param config the pixel config of the source buffer * @param buffer memory to read pixels from * @param rowBytes number of bytes bewtween consecutive rows. Zero * means rows are tightly packed. */ void writeTexturePixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes) { this->internalWriteTexturePixels(texture, left, top, width, height, config, buffer, rowBytes, 0); } /** * Copies all texels from one texture to another. * @param src the texture to copy from. * @param dst the render target to copy to. */ void copyTexture(GrTexture* src, GrRenderTarget* dst); /** * Resolves a render target that has MSAA. The intermediate MSAA buffer is * downsampled to the associated GrTexture (accessible via * GrRenderTarget::asTexture()). Any pending draws to the render target will * be executed before the resolve. * * This is only necessary when a client wants to access the object directly * using the underlying graphics API. GrContext will detect when it must * perform a resolve to a GrTexture used as the source of a draw or before * reading pixels back from a GrTexture or GrRenderTarget. */ void resolveRenderTarget(GrRenderTarget* target); /** * Applies a 1D convolution kernel in the X direction to a rectangle of * pixels from a given texture. * @param texture the texture to read from * @param rect the destination rectangle * @param kernel the convolution kernel (kernelWidth elements) * @param kernelWidth the width of the convolution kernel */ void convolveInX(GrTexture* texture, const SkRect& rect, const float* kernel, int kernelWidth); /** * Applies a 1D convolution kernel in the Y direction to a rectangle of * pixels from a given texture. * direction. * @param texture the texture to read from * @param rect the destination rectangle * @param kernel the convolution kernel (kernelWidth elements) * @param kernelWidth the width of the convolution kernel */ void convolveInY(GrTexture* texture, const SkRect& rect, const float* kernel, int kernelWidth); /////////////////////////////////////////////////////////////////////////// // Helpers class AutoRenderTarget : ::GrNoncopyable { public: AutoRenderTarget(GrContext* context, GrRenderTarget* target) { fContext = NULL; fPrevTarget = context->getRenderTarget(); if (fPrevTarget != target) { context->setRenderTarget(target); fContext = context; } } ~AutoRenderTarget() { if (fContext) { fContext->setRenderTarget(fPrevTarget); } } private: GrContext* fContext; GrRenderTarget* fPrevTarget; }; /////////////////////////////////////////////////////////////////////////// // Functions intended for internal use only. GrGpu* getGpu() { return fGpu; } const GrGpu* getGpu() const { return fGpu; } GrFontCache* getFontCache() { return fFontCache; } GrDrawTarget* getTextTarget(const GrPaint& paint); void flushText(); const GrIndexBuffer* getQuadIndexBuffer() const; void resetStats(); const GrGpuStats& getStats() const; void printStats() const; /** * Stencil buffers add themselves to the cache using * addAndLockStencilBuffer. When a SB's RT-attachment count * reaches zero the SB unlocks itself using unlockStencilBuffer and is * eligible for purging. findStencilBuffer is called to check the cache for * a SB that matching an RT's criteria. If a match is found that has been * unlocked (its attachment count has reached 0) then it will be relocked. */ GrResourceEntry* addAndLockStencilBuffer(GrStencilBuffer* sb); void unlockStencilBuffer(GrResourceEntry* sbEntry); GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt); private: // used to keep track of when we need to flush the draw buffer enum DrawCategory { kBuffered_DrawCategory, // last draw was inserted in draw buffer kUnbuffered_DrawCategory, // last draw was not inserted in the draw buffer kText_DrawCategory // text context was last to draw }; DrawCategory fLastDrawCategory; GrGpu* fGpu; GrResourceCache* fTextureCache; GrFontCache* fFontCache; GrPathRendererChain* fPathRendererChain; GrVertexBufferAllocPool* fDrawBufferVBAllocPool; GrIndexBufferAllocPool* fDrawBufferIBAllocPool; GrInOrderDrawBuffer* fDrawBuffer; GrIndexBuffer* fAAFillRectIndexBuffer; GrIndexBuffer* fAAStrokeRectIndexBuffer; int fMaxOffscreenAASize; GrContext(GrGpu* gpu); void fillAARect(GrDrawTarget* target, const GrRect& devRect, bool useVertexCoverage); void strokeAARect(GrDrawTarget* target, const GrRect& devRect, const GrVec& devStrokeSize, bool useVertexCoverage); inline int aaFillRectIndexCount() const; GrIndexBuffer* aaFillRectIndexBuffer(); inline int aaStrokeRectIndexCount() const; GrIndexBuffer* aaStrokeRectIndexBuffer(); void setupDrawBuffer(); void flushDrawBuffer(); void setPaint(const GrPaint& paint, GrDrawTarget* target); GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType); GrPathRenderer* getPathRenderer(const GrPath& path, GrPathFill fill, bool antiAlias); struct OffscreenRecord; // determines whether offscreen AA should be applied bool doOffscreenAA(GrDrawTarget* target, bool isHairLines) const; // attempts to setup offscreen AA. All paint state must be transferred to // target by the time this is called. bool prepareForOffscreenAA(GrDrawTarget* target, bool requireStencil, const GrIRect& boundRect, GrPathRenderer* pr, OffscreenRecord* record); // sets up target to draw coverage to the supersampled render target void setupOffscreenAAPass1(GrDrawTarget* target, const GrIRect& boundRect, int tileX, int tileY, OffscreenRecord* record); // sets up target to sample coverage of supersampled render target back // to the main render target using stage kOffscreenStage. void doOffscreenAAPass2(GrDrawTarget* target, const GrPaint& paint, const GrIRect& boundRect, int tileX, int tileY, OffscreenRecord* record); // restored the draw target state and releases offscreen target to cache void cleanupOffscreenAA(GrDrawTarget* target, GrPathRenderer* pr, OffscreenRecord* record); void convolve(GrTexture* texture, const SkRect& rect, float imageIncrement[2], const float* kernel, int kernelWidth); /** * Flags to the internal read/write pixels funcs */ enum PixelOpsFlags { kDontFlush_PixelOpsFlag = 0x1, }; bool internalReadRenderTargetPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes, uint32_t flags); void internalWriteRenderTargetPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig, const void* buffer, size_t rowBytes, uint32_t flags); bool internalReadTexturePixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes, uint32_t flags); void internalWriteTexturePixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes, uint32_t flags); // needed for access to internalWriteTexturePixels. TODO: make GrContext // be a facade for an internal class. Then functions that are public on the // internal class would have only be callable in src/gpu. The facade would // only have to functions necessary for clients. friend class GrAtlas; // computes vertex layout bits based on the paint. If paint expresses // a texture for a stage, the stage coords will be bound to postitions // unless hasTexCoords[s]==true in which case stage s's input coords // are bound to tex coord index s. hasTexCoords == NULL is a shortcut // for an array where all the values are false. static int PaintStageVertexLayoutBits( const GrPaint& paint, const bool hasTexCoords[GrPaint::kTotalStages]); }; /** * Save/restore the view-matrix in the context. */ class GrAutoMatrix : GrNoncopyable { public: GrAutoMatrix() : fContext(NULL) {} GrAutoMatrix(GrContext* ctx) : fContext(ctx) { fMatrix = ctx->getMatrix(); } GrAutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) { fMatrix = ctx->getMatrix(); ctx->setMatrix(matrix); } void set(GrContext* ctx) { if (NULL != fContext) { fContext->setMatrix(fMatrix); } fMatrix = ctx->getMatrix(); fContext = ctx; } void set(GrContext* ctx, const GrMatrix& matrix) { if (NULL != fContext) { fContext->setMatrix(fMatrix); } fMatrix = ctx->getMatrix(); ctx->setMatrix(matrix); fContext = ctx; } ~GrAutoMatrix() { if (NULL != fContext) { fContext->setMatrix(fMatrix); } } private: GrContext* fContext; GrMatrix fMatrix; }; /** * Gets and locks a scratch texture from a descriptor using * either exact or approximate criteria. Unlocks texture in * the destructor. */ class GrAutoScratchTexture : ::GrNoncopyable { public: GrAutoScratchTexture() : fContext(NULL) { } GrAutoScratchTexture(GrContext* context, const GrTextureDesc& desc, GrContext::ScratchTexMatch match = GrContext::kApprox_ScratchTexMatch) : fContext(NULL) { this->set(context, desc, match); } ~GrAutoScratchTexture() { if (NULL != fContext) { fContext->unlockTexture(fEntry); } } GrTexture* set(GrContext* context, const GrTextureDesc& desc, GrContext::ScratchTexMatch match = GrContext::kApprox_ScratchTexMatch) { if (NULL != fContext) { fContext->unlockTexture(fEntry); } fContext = context; if (NULL != fContext) { fEntry = fContext->lockScratchTexture(desc, match); GrTexture* ret = fEntry.texture(); if (NULL == ret) { fContext = NULL; } return ret; } else { return NULL; } } GrTexture* texture() { return fEntry.texture(); } private: GrContext* fContext; GrContext::TextureCacheEntry fEntry; }; #endif