|
1 /* |
|
2 * Copyright 2011 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #ifndef GrGpu_DEFINED |
|
9 #define GrGpu_DEFINED |
|
10 |
|
11 #include "GrDrawTarget.h" |
|
12 #include "GrClipMaskManager.h" |
|
13 #include "SkPath.h" |
|
14 |
|
15 class GrContext; |
|
16 class GrIndexBufferAllocPool; |
|
17 class GrPath; |
|
18 class GrPathRenderer; |
|
19 class GrPathRendererChain; |
|
20 class GrResource; |
|
21 class GrStencilBuffer; |
|
22 class GrVertexBufferAllocPool; |
|
23 |
|
24 class GrGpu : public GrDrawTarget { |
|
25 public: |
|
26 |
|
27 /** |
|
28 * Additional blend coefficients for dual source blending, not exposed |
|
29 * through GrPaint/GrContext. |
|
30 */ |
|
31 enum ExtendedBlendCoeffs { |
|
32 // source 2 refers to second output color when |
|
33 // using dual source blending. |
|
34 kS2C_GrBlendCoeff = kPublicGrBlendCoeffCount, |
|
35 kIS2C_GrBlendCoeff, |
|
36 kS2A_GrBlendCoeff, |
|
37 kIS2A_GrBlendCoeff, |
|
38 |
|
39 kTotalGrBlendCoeffCount |
|
40 }; |
|
41 |
|
42 /** |
|
43 * Create an instance of GrGpu that matches the specified backend. If the requested backend is |
|
44 * not supported (at compile-time or run-time) this returns NULL. The context will not be |
|
45 * fully constructed and should not be used by GrGpu until after this function returns. |
|
46 */ |
|
47 static GrGpu* Create(GrBackend, GrBackendContext, GrContext* context); |
|
48 |
|
49 //////////////////////////////////////////////////////////////////////////// |
|
50 |
|
51 GrGpu(GrContext* context); |
|
52 virtual ~GrGpu(); |
|
53 |
|
54 GrContext* getContext() { return this->INHERITED::getContext(); } |
|
55 const GrContext* getContext() const { return this->INHERITED::getContext(); } |
|
56 |
|
57 /** |
|
58 * The GrGpu object normally assumes that no outsider is setting state |
|
59 * within the underlying 3D API's context/device/whatever. This call informs |
|
60 * the GrGpu that the state was modified and it shouldn't make assumptions |
|
61 * about the state. |
|
62 */ |
|
63 void markContextDirty(uint32_t state = kAll_GrBackendState) { |
|
64 fResetBits |= state; |
|
65 } |
|
66 |
|
67 void unimpl(const char[]); |
|
68 |
|
69 /** |
|
70 * Creates a texture object. If desc width or height is not a power of |
|
71 * two but underlying API requires a power of two texture then srcData |
|
72 * will be embedded in a power of two texture. The extra width and height |
|
73 * is filled as though srcData were rendered clamped into the texture. |
|
74 * |
|
75 * If kRenderTarget_TextureFlag is specified the GrRenderTarget is |
|
76 * accessible via GrTexture::asRenderTarget(). The texture will hold a ref |
|
77 * on the render target until the texture is destroyed. |
|
78 * |
|
79 * @param desc describes the texture to be created. |
|
80 * @param srcData texel data to load texture. Begins with full-size |
|
81 * palette data for paletted textures. Contains width* |
|
82 * height texels. If NULL texture data is uninitialized. |
|
83 * |
|
84 * @return The texture object if successful, otherwise NULL. |
|
85 */ |
|
86 GrTexture* createTexture(const GrTextureDesc& desc, |
|
87 const void* srcData, size_t rowBytes); |
|
88 |
|
89 /** |
|
90 * Implements GrContext::wrapBackendTexture |
|
91 */ |
|
92 GrTexture* wrapBackendTexture(const GrBackendTextureDesc&); |
|
93 |
|
94 /** |
|
95 * Implements GrContext::wrapBackendTexture |
|
96 */ |
|
97 GrRenderTarget* wrapBackendRenderTarget(const GrBackendRenderTargetDesc&); |
|
98 |
|
99 /** |
|
100 * Creates a vertex buffer. |
|
101 * |
|
102 * @param size size in bytes of the vertex buffer |
|
103 * @param dynamic hints whether the data will be frequently changed |
|
104 * by either GrVertexBuffer::lock or |
|
105 * GrVertexBuffer::updateData. |
|
106 * |
|
107 * @return The vertex buffer if successful, otherwise NULL. |
|
108 */ |
|
109 GrVertexBuffer* createVertexBuffer(size_t size, bool dynamic); |
|
110 |
|
111 /** |
|
112 * Creates an index buffer. |
|
113 * |
|
114 * @param size size in bytes of the index buffer |
|
115 * @param dynamic hints whether the data will be frequently changed |
|
116 * by either GrIndexBuffer::lock or |
|
117 * GrIndexBuffer::updateData. |
|
118 * |
|
119 * @return The index buffer if successful, otherwise NULL. |
|
120 */ |
|
121 GrIndexBuffer* createIndexBuffer(size_t size, bool dynamic); |
|
122 |
|
123 /** |
|
124 * Creates a path object that can be stenciled using stencilPath(). It is |
|
125 * only legal to call this if the caps report support for path stenciling. |
|
126 */ |
|
127 GrPath* createPath(const SkPath& path, const SkStrokeRec& stroke); |
|
128 |
|
129 /** |
|
130 * Returns an index buffer that can be used to render quads. |
|
131 * Six indices per quad: 0, 1, 2, 0, 2, 3, etc. |
|
132 * The max number of quads can be queried using GrIndexBuffer::maxQuads(). |
|
133 * Draw with kTriangles_GrPrimitiveType |
|
134 * @ return the quad index buffer |
|
135 */ |
|
136 const GrIndexBuffer* getQuadIndexBuffer() const; |
|
137 |
|
138 /** |
|
139 * Resolves MSAA. |
|
140 */ |
|
141 void resolveRenderTarget(GrRenderTarget* target); |
|
142 |
|
143 /** |
|
144 * Ensures that the current render target is actually set in the |
|
145 * underlying 3D API. Used when client wants to use 3D API to directly |
|
146 * render to the RT. |
|
147 */ |
|
148 void forceRenderTargetFlush(); |
|
149 |
|
150 /** |
|
151 * Gets a preferred 8888 config to use for writing/reading pixel data to/from a surface with |
|
152 * config surfaceConfig. The returned config must have at least as many bits per channel as the |
|
153 * readConfig or writeConfig param. |
|
154 */ |
|
155 virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig readConfig, |
|
156 GrPixelConfig surfaceConfig) const { |
|
157 return readConfig; |
|
158 } |
|
159 virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig, |
|
160 GrPixelConfig surfaceConfig) const { |
|
161 return writeConfig; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Called before uploading writing pixels to a GrTexture when the src pixel config doesn't |
|
166 * match the texture's config. |
|
167 */ |
|
168 virtual bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const = 0; |
|
169 |
|
170 /** |
|
171 * OpenGL's readPixels returns the result bottom-to-top while the skia |
|
172 * API is top-to-bottom. Thus we have to do a y-axis flip. The obvious |
|
173 * solution is to have the subclass do the flip using either the CPU or GPU. |
|
174 * However, the caller (GrContext) may have transformations to apply and can |
|
175 * simply fold in the y-flip for free. On the other hand, the subclass may |
|
176 * be able to do it for free itself. For example, the subclass may have to |
|
177 * do memcpys to handle rowBytes that aren't tight. It could do the y-flip |
|
178 * concurrently. |
|
179 * |
|
180 * This function returns true if a y-flip is required to put the pixels in |
|
181 * top-to-bottom order and the subclass cannot do it for free. |
|
182 * |
|
183 * See read pixels for the params |
|
184 * @return true if calling readPixels with the same set of params will |
|
185 * produce bottom-to-top data |
|
186 */ |
|
187 virtual bool readPixelsWillPayForYFlip(GrRenderTarget* renderTarget, |
|
188 int left, int top, |
|
189 int width, int height, |
|
190 GrPixelConfig config, |
|
191 size_t rowBytes) const = 0; |
|
192 /** |
|
193 * This should return true if reading a NxM rectangle of pixels from a |
|
194 * render target is faster if the target has dimensons N and M and the read |
|
195 * rectangle has its top-left at 0,0. |
|
196 */ |
|
197 virtual bool fullReadPixelsIsFasterThanPartial() const { return false; }; |
|
198 |
|
199 /** |
|
200 * Reads a rectangle of pixels from a render target. |
|
201 * |
|
202 * @param renderTarget the render target to read from. NULL means the |
|
203 * current render target. |
|
204 * @param left left edge of the rectangle to read (inclusive) |
|
205 * @param top top edge of the rectangle to read (inclusive) |
|
206 * @param width width of rectangle to read in pixels. |
|
207 * @param height height of rectangle to read in pixels. |
|
208 * @param config the pixel config of the destination buffer |
|
209 * @param buffer memory to read the rectangle into. |
|
210 * @param rowBytes the number of bytes between consecutive rows. Zero |
|
211 * means rows are tightly packed. |
|
212 * @param invertY buffer should be populated bottom-to-top as opposed |
|
213 * to top-to-bottom (skia's usual order) |
|
214 * |
|
215 * @return true if the read succeeded, false if not. The read can fail |
|
216 * because of a unsupported pixel config or because no render |
|
217 * target is currently set. |
|
218 */ |
|
219 bool readPixels(GrRenderTarget* renderTarget, |
|
220 int left, int top, int width, int height, |
|
221 GrPixelConfig config, void* buffer, size_t rowBytes); |
|
222 |
|
223 /** |
|
224 * Updates the pixels in a rectangle of a texture. |
|
225 * |
|
226 * @param left left edge of the rectangle to write (inclusive) |
|
227 * @param top top edge of the rectangle to write (inclusive) |
|
228 * @param width width of rectangle to write in pixels. |
|
229 * @param height height of rectangle to write in pixels. |
|
230 * @param config the pixel config of the source buffer |
|
231 * @param buffer memory to read pixels from |
|
232 * @param rowBytes number of bytes between consecutive rows. Zero |
|
233 * means rows are tightly packed. |
|
234 */ |
|
235 bool writeTexturePixels(GrTexture* texture, |
|
236 int left, int top, int width, int height, |
|
237 GrPixelConfig config, const void* buffer, |
|
238 size_t rowBytes); |
|
239 |
|
240 /** |
|
241 * Called to tell Gpu object that all GrResources have been lost and should |
|
242 * be abandoned. Overrides must call INHERITED::abandonResources(). |
|
243 */ |
|
244 virtual void abandonResources(); |
|
245 |
|
246 /** |
|
247 * Called to tell Gpu object to release all GrResources. Overrides must call |
|
248 * INHERITED::releaseResources(). |
|
249 */ |
|
250 void releaseResources(); |
|
251 |
|
252 /** |
|
253 * Add resource to list of resources. Should only be called by GrResource. |
|
254 * @param resource the resource to add. |
|
255 */ |
|
256 void insertResource(GrResource* resource); |
|
257 |
|
258 /** |
|
259 * Remove resource from list of resources. Should only be called by |
|
260 * GrResource. |
|
261 * @param resource the resource to remove. |
|
262 */ |
|
263 void removeResource(GrResource* resource); |
|
264 |
|
265 // GrDrawTarget overrides |
|
266 virtual void clear(const SkIRect* rect, |
|
267 GrColor color, |
|
268 bool canIgnoreRect, |
|
269 GrRenderTarget* renderTarget = NULL) SK_OVERRIDE; |
|
270 |
|
271 virtual void purgeResources() SK_OVERRIDE { |
|
272 // The clip mask manager can rebuild all its clip masks so just |
|
273 // get rid of them all. |
|
274 fClipMaskManager.releaseResources(); |
|
275 } |
|
276 |
|
277 // After the client interacts directly with the 3D context state the GrGpu |
|
278 // must resync its internal state and assumptions about 3D context state. |
|
279 // Each time this occurs the GrGpu bumps a timestamp. |
|
280 // state of the 3D context |
|
281 // At 10 resets / frame and 60fps a 64bit timestamp will overflow in about |
|
282 // a billion years. |
|
283 typedef uint64_t ResetTimestamp; |
|
284 |
|
285 // This timestamp is always older than the current timestamp |
|
286 static const ResetTimestamp kExpiredTimestamp = 0; |
|
287 // Returns a timestamp based on the number of times the context was reset. |
|
288 // This timestamp can be used to lazily detect when cached 3D context state |
|
289 // is dirty. |
|
290 ResetTimestamp getResetTimestamp() const { |
|
291 return fResetTimestamp; |
|
292 } |
|
293 |
|
294 /** |
|
295 * These methods are called by the clip manager's setupClipping function |
|
296 * which (called as part of GrGpu's implementation of onDraw and |
|
297 * onStencilPath member functions.) The GrGpu subclass should flush the |
|
298 * stencil state to the 3D API in its implementation of flushGraphicsState. |
|
299 */ |
|
300 void enableScissor(const SkIRect& rect) { |
|
301 fScissorState.fEnabled = true; |
|
302 fScissorState.fRect = rect; |
|
303 } |
|
304 void disableScissor() { fScissorState.fEnabled = false; } |
|
305 |
|
306 /** |
|
307 * Like the scissor methods above this is called by setupClipping and |
|
308 * should be flushed by the GrGpu subclass in flushGraphicsState. These |
|
309 * stencil settings should be used in place of those on the GrDrawState. |
|
310 * They have been adjusted to account for any interactions between the |
|
311 * GrDrawState's stencil settings and stencil clipping. |
|
312 */ |
|
313 void setStencilSettings(const GrStencilSettings& settings) { |
|
314 fStencilSettings = settings; |
|
315 } |
|
316 void disableStencil() { fStencilSettings.setDisabled(); } |
|
317 |
|
318 // GrGpu subclass sets clip bit in the stencil buffer. The subclass is |
|
319 // free to clear the remaining bits to zero if masked clears are more |
|
320 // expensive than clearing all bits. |
|
321 virtual void clearStencilClip(const SkIRect& rect, bool insideClip) = 0; |
|
322 |
|
323 enum PrivateDrawStateStateBits { |
|
324 kFirstBit = (GrDrawState::kLastPublicStateBit << 1), |
|
325 |
|
326 kModifyStencilClip_StateBit = kFirstBit, // allows draws to modify |
|
327 // stencil bits used for |
|
328 // clipping. |
|
329 }; |
|
330 |
|
331 void getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings); |
|
332 |
|
333 protected: |
|
334 enum DrawType { |
|
335 kDrawPoints_DrawType, |
|
336 kDrawLines_DrawType, |
|
337 kDrawTriangles_DrawType, |
|
338 kStencilPath_DrawType, |
|
339 kDrawPath_DrawType, |
|
340 }; |
|
341 |
|
342 DrawType PrimTypeToDrawType(GrPrimitiveType type) { |
|
343 switch (type) { |
|
344 case kTriangles_GrPrimitiveType: |
|
345 case kTriangleStrip_GrPrimitiveType: |
|
346 case kTriangleFan_GrPrimitiveType: |
|
347 return kDrawTriangles_DrawType; |
|
348 case kPoints_GrPrimitiveType: |
|
349 return kDrawPoints_DrawType; |
|
350 case kLines_GrPrimitiveType: |
|
351 case kLineStrip_GrPrimitiveType: |
|
352 return kDrawLines_DrawType; |
|
353 default: |
|
354 GrCrash("Unexpected primitive type"); |
|
355 return kDrawTriangles_DrawType; |
|
356 } |
|
357 } |
|
358 |
|
359 // prepares clip flushes gpu state before a draw |
|
360 bool setupClipAndFlushState(DrawType, |
|
361 const GrDeviceCoordTexture* dstCopy, |
|
362 GrDrawState::AutoRestoreEffects* are, |
|
363 const SkRect* devBounds); |
|
364 |
|
365 // Functions used to map clip-respecting stencil tests into normal |
|
366 // stencil funcs supported by GPUs. |
|
367 static GrStencilFunc ConvertStencilFunc(bool stencilInClip, |
|
368 GrStencilFunc func); |
|
369 static void ConvertStencilFuncAndMask(GrStencilFunc func, |
|
370 bool clipInStencil, |
|
371 unsigned int clipBit, |
|
372 unsigned int userBits, |
|
373 unsigned int* ref, |
|
374 unsigned int* mask); |
|
375 |
|
376 GrClipMaskManager fClipMaskManager; |
|
377 |
|
378 struct GeometryPoolState { |
|
379 const GrVertexBuffer* fPoolVertexBuffer; |
|
380 int fPoolStartVertex; |
|
381 |
|
382 const GrIndexBuffer* fPoolIndexBuffer; |
|
383 int fPoolStartIndex; |
|
384 }; |
|
385 const GeometryPoolState& getGeomPoolState() { |
|
386 return fGeomPoolStateStack.back(); |
|
387 } |
|
388 |
|
389 // The state of the scissor is controlled by the clip manager |
|
390 struct ScissorState { |
|
391 bool fEnabled; |
|
392 SkIRect fRect; |
|
393 } fScissorState; |
|
394 |
|
395 // The final stencil settings to use as determined by the clip manager. |
|
396 GrStencilSettings fStencilSettings; |
|
397 |
|
398 // Helpers for setting up geometry state |
|
399 void finalizeReservedVertices(); |
|
400 void finalizeReservedIndices(); |
|
401 |
|
402 private: |
|
403 // GrDrawTarget overrides |
|
404 virtual bool onReserveVertexSpace(size_t vertexSize, int vertexCount, void** vertices) SK_OVERRIDE; |
|
405 virtual bool onReserveIndexSpace(int indexCount, void** indices) SK_OVERRIDE; |
|
406 virtual void releaseReservedVertexSpace() SK_OVERRIDE; |
|
407 virtual void releaseReservedIndexSpace() SK_OVERRIDE; |
|
408 virtual void onSetVertexSourceToArray(const void* vertexArray, int vertexCount) SK_OVERRIDE; |
|
409 virtual void onSetIndexSourceToArray(const void* indexArray, int indexCount) SK_OVERRIDE; |
|
410 virtual void releaseVertexArray() SK_OVERRIDE; |
|
411 virtual void releaseIndexArray() SK_OVERRIDE; |
|
412 virtual void geometrySourceWillPush() SK_OVERRIDE; |
|
413 virtual void geometrySourceWillPop(const GeometrySrcState& restoredState) SK_OVERRIDE; |
|
414 |
|
415 |
|
416 // called when the 3D context state is unknown. Subclass should emit any |
|
417 // assumed 3D context state and dirty any state cache. |
|
418 virtual void onResetContext(uint32_t resetBits) = 0; |
|
419 |
|
420 // overridden by backend-specific derived class to create objects. |
|
421 virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, |
|
422 const void* srcData, |
|
423 size_t rowBytes) = 0; |
|
424 virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) = 0; |
|
425 virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0; |
|
426 virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) = 0; |
|
427 virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) = 0; |
|
428 virtual GrPath* onCreatePath(const SkPath& path, const SkStrokeRec&) = 0; |
|
429 |
|
430 // overridden by backend-specific derived class to perform the clear and |
|
431 // clearRect. NULL rect means clear whole target. If canIgnoreRect is |
|
432 // true, it is okay to perform a full clear instead of a partial clear |
|
433 virtual void onClear(const SkIRect* rect, GrColor color, bool canIgnoreRect) = 0; |
|
434 |
|
435 // overridden by backend-specific derived class to perform the draw call. |
|
436 virtual void onGpuDraw(const DrawInfo&) = 0; |
|
437 |
|
438 // overridden by backend-specific derived class to perform the path stenciling. |
|
439 virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0; |
|
440 virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) = 0; |
|
441 |
|
442 // overridden by backend-specific derived class to perform flush |
|
443 virtual void onForceRenderTargetFlush() = 0; |
|
444 |
|
445 // overridden by backend-specific derived class to perform the read pixels. |
|
446 virtual bool onReadPixels(GrRenderTarget* target, |
|
447 int left, int top, int width, int height, |
|
448 GrPixelConfig, |
|
449 void* buffer, |
|
450 size_t rowBytes) = 0; |
|
451 |
|
452 // overridden by backend-specific derived class to perform the texture update |
|
453 virtual bool onWriteTexturePixels(GrTexture* texture, |
|
454 int left, int top, int width, int height, |
|
455 GrPixelConfig config, const void* buffer, |
|
456 size_t rowBytes) = 0; |
|
457 |
|
458 // overridden by backend-specific derived class to perform the resolve |
|
459 virtual void onResolveRenderTarget(GrRenderTarget* target) = 0; |
|
460 |
|
461 // width and height may be larger than rt (if underlying API allows it). |
|
462 // Should attach the SB to the RT. Returns false if compatible sb could |
|
463 // not be created. |
|
464 virtual bool createStencilBufferForRenderTarget(GrRenderTarget*, int width, int height) = 0; |
|
465 |
|
466 // attaches an existing SB to an existing RT. |
|
467 virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer*, GrRenderTarget*) = 0; |
|
468 |
|
469 // The GrGpu typically records the clients requested state and then flushes |
|
470 // deltas from previous state at draw time. This function does the |
|
471 // backend-specific flush of the state. |
|
472 // returns false if current state is unsupported. |
|
473 virtual bool flushGraphicsState(DrawType, const GrDeviceCoordTexture* dstCopy) = 0; |
|
474 |
|
475 // clears the entire stencil buffer to 0 |
|
476 virtual void clearStencil() = 0; |
|
477 |
|
478 // Given a rt, find or create a stencil buffer and attach it |
|
479 bool attachStencilBufferToRenderTarget(GrRenderTarget* target); |
|
480 |
|
481 // GrDrawTarget overrides |
|
482 virtual void onDraw(const DrawInfo&) SK_OVERRIDE; |
|
483 virtual void onStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE; |
|
484 virtual void onDrawPath(const GrPath*, SkPath::FillType, |
|
485 const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE; |
|
486 |
|
487 // readies the pools to provide vertex/index data. |
|
488 void prepareVertexPool(); |
|
489 void prepareIndexPool(); |
|
490 |
|
491 void resetContext() { |
|
492 // We call this because the client may have messed with the |
|
493 // stencil buffer. Perhaps we should detect whether it is a |
|
494 // internally created stencil buffer and if so skip the invalidate. |
|
495 fClipMaskManager.invalidateStencilMask(); |
|
496 this->onResetContext(fResetBits); |
|
497 fResetBits = 0; |
|
498 ++fResetTimestamp; |
|
499 } |
|
500 |
|
501 void handleDirtyContext() { |
|
502 if (fResetBits) { |
|
503 this->resetContext(); |
|
504 } |
|
505 } |
|
506 |
|
507 enum { |
|
508 kPreallocGeomPoolStateStackCnt = 4, |
|
509 }; |
|
510 typedef SkTInternalLList<GrResource> ResourceList; |
|
511 SkSTArray<kPreallocGeomPoolStateStackCnt, GeometryPoolState, true> fGeomPoolStateStack; |
|
512 ResetTimestamp fResetTimestamp; |
|
513 uint32_t fResetBits; |
|
514 GrVertexBufferAllocPool* fVertexPool; |
|
515 GrIndexBufferAllocPool* fIndexPool; |
|
516 // counts number of uses of vertex/index pool in the geometry stack |
|
517 int fVertexPoolUseCnt; |
|
518 int fIndexPoolUseCnt; |
|
519 // these are mutable so they can be created on-demand |
|
520 mutable GrIndexBuffer* fQuadIndexBuffer; |
|
521 // Used to abandon/release all resources created by this GrGpu. TODO: Move this |
|
522 // functionality to GrResourceCache. |
|
523 ResourceList fResourceList; |
|
524 |
|
525 typedef GrDrawTarget INHERITED; |
|
526 }; |
|
527 |
|
528 #endif |