-/*\r
- Copyright 2010 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#ifndef GrContext_DEFINED\r
-#define GrContext_DEFINED\r
-\r
-#include "GrClip.h"\r
-#include "GrGpu.h"\r
-#include "GrTextureCache.h"\r
-#include "GrPaint.h"\r
-\r
-class GrFontCache;\r
-class GrPathIter;\r
-class GrVertexBufferAllocPool;\r
-class GrIndexBufferAllocPool;\r
-class GrInOrderDrawBuffer;\r
-class GrPathRenderer;\r
-\r
-class GrContext : public GrRefCnt {\r
-public:\r
- /**\r
- * Creates a GrContext from within a 3D context.\r
- */\r
- static GrContext* Create(GrGpu::Engine engine,\r
- GrGpu::Platform3DContext context3D);\r
-\r
- /**\r
- * Helper to create a opengl-shader based context\r
- */\r
- static GrContext* CreateGLShaderContext();\r
-\r
- virtual ~GrContext();\r
-\r
- /**\r
- * The GrContext normally assumes that no outsider is setting state\r
- * within the underlying 3D API's context/device/whatever. This call informs\r
- * the context that the state was modified and it should resend. Shouldn't\r
- * be called frequently for good performance.\r
- */\r
- void resetContext();\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Textures\r
-\r
- /**\r
- * Abandons all textures. Call this if you have lost the associated GPU\r
- * context, and thus internal texture references/IDs are now invalid.\r
- */\r
- void abandonAllTextures();\r
-\r
- /**\r
- * Search for an entry with the same Key. If found, "lock" it and return it.\r
- * If not found, return null.\r
- */\r
- GrTextureEntry* findAndLockTexture(GrTextureKey*,\r
- const GrSamplerState&);\r
-\r
-\r
- /**\r
- * Create a new entry, based on the specified key and texture, and return\r
- * its "locked" entry.\r
- *\r
- * Ownership of the texture is transferred to the Entry, which will unref()\r
- * it when we are purged or deleted.\r
- */\r
- GrTextureEntry* createAndLockTexture(GrTextureKey* key,\r
- const GrSamplerState&,\r
- const GrGpu::TextureDesc&,\r
- void* srcData, size_t rowBytes);\r
-\r
- /**\r
- * When done with an entry, call unlockTexture(entry) on it, which returns\r
- * it to the cache, where it may be purged.\r
- */\r
- void unlockTexture(GrTextureEntry* entry);\r
-\r
- /**\r
- * Removes an texture from the cache. This prevents the texture from\r
- * being found by a subsequent findAndLockTexture() until it is\r
- * reattached. The entry still counts against the cache's budget and should\r
- * be reattached when exclusive access is no longer needed.\r
- */\r
- void detachCachedTexture(GrTextureEntry*);\r
-\r
- /**\r
- * Reattaches a texture to the cache and unlocks it. Allows it to be found\r
- * by a subsequent findAndLock or be purged (provided its lock count is\r
- * now 0.)\r
- */\r
- void reattachAndUnlockCachedTexture(GrTextureEntry*);\r
-\r
- /**\r
- * Creates a texture that is outside the cache. Does not count against\r
- * cache's budget.\r
- */\r
- GrTexture* createUncachedTexture(const GrGpu::TextureDesc&,\r
- void* srcData,\r
- size_t rowBytes);\r
-\r
- /**\r
- * Returns true if the specified use of an indexed texture is supported.\r
- */\r
- bool supportsIndex8PixelConfig(const GrSamplerState&, int width, int height);\r
-\r
- /**\r
- * Return the current texture cache limits.\r
- *\r
- * @param maxTextures If non-null, returns maximum number of textures that\r
- * can be held in the cache.\r
- * @param maxTextureBytes If non-null, returns maximum number of bytes of\r
- * texture memory that can be held in the cache.\r
- */\r
- void getTextureCacheLimits(int* maxTextures, size_t* maxTextureBytes) const;\r
-\r
- /**\r
- * Specify the texture cache limits. If the current cache exceeds either\r
- * of these, it will be purged (LRU) to keep the cache within these limits.\r
- *\r
- * @param maxTextures The maximum number of textures that can be held in\r
- * the cache.\r
- * @param maxTextureBytes The maximum number of bytes of texture memory\r
- * that can be held in the cache.\r
- */\r
- void setTextureCacheLimits(int maxTextures, size_t maxTextureBytes);\r
-\r
- /**\r
- * Return the max width or height of a texture supported by the current gpu\r
- */\r
- int getMaxTextureDimension();\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Render targets\r
-\r
- /**\r
- * Wraps an externally-created rendertarget in a GrRenderTarget.\r
- * @param platformRenderTarget 3D API-specific render target identifier\r
- * e.g. in GL platforamRenderTarget is an FBO \r
- * id.\r
- * @param stencilBits the number of stencil bits that the render\r
- * target has.\r
- * @param width width of the render target.\r
- * @param height height of the render target.\r
- */\r
- GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,\r
- int stencilBits,\r
- int width, int height);\r
-\r
- /**\r
- * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and\r
- * viewport state from the underlying 3D API and wraps it in a\r
- * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the\r
- * underlying object in its destructor and it is up to caller to guarantee\r
- * that it remains valid while the GrRenderTarget is used.\r
- *\r
- * @return the newly created GrRenderTarget\r
- */\r
- GrRenderTarget* createRenderTargetFrom3DApiState() {\r
- return fGpu->createRenderTargetFrom3DApiState();\r
- }\r
-\r
- /**\r
- * Sets the render target.\r
- * @param target the render target to set. (should not be NULL.)\r
- */\r
- void setRenderTarget(GrRenderTarget* target);\r
-\r
- /**\r
- * Gets the current render target.\r
- * @return the currently bound render target. Should never be NULL.\r
- */\r
- const GrRenderTarget* getRenderTarget() const;\r
- GrRenderTarget* getRenderTarget();\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Matrix state\r
-\r
- /**\r
- * Gets the current transformation matrix.\r
- * @return the current matrix.\r
- */\r
- const GrMatrix& getMatrix() const;\r
-\r
- /**\r
- * Sets the transformation matrix.\r
- * @param m the matrix to set.\r
- */\r
- void setMatrix(const GrMatrix& m);\r
-\r
- /**\r
- * Concats the current matrix. The passed matrix is applied before the\r
- * current matrix.\r
- * @param m the matrix to concat.\r
- */\r
- void concatMatrix(const GrMatrix& m) const;\r
-\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Clip state\r
- /**\r
- * Gets the current clip.\r
- * @return the current clip.\r
- */\r
- const GrClip& getClip() const { return fGpu->getClip(); }\r
-\r
- /**\r
- * Sets the clip.\r
- * @param clip the clip to set.\r
- */\r
- void setClip(const GrClip& clip);\r
-\r
- /**\r
- * Convenience method for setting the clip to a rect.\r
- * @param rect the rect to set as the new clip.\r
- */\r
- void setClip(const GrIRect& rect);\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Draws\r
-\r
- /**\r
- * Erase the entire render target, ignoring any clips\r
- */\r
- void eraseColor(GrColor color);\r
-\r
- /**\r
- * Draw everywhere (respecting the clip) with the paint.\r
- */\r
- void drawPaint(const GrPaint& paint);\r
-\r
- /**\r
- * Draw the rect using a paint.\r
- * @param paint describes how to color pixels.\r
- * @param strokeWidth If strokeWidth < 0, then the rect is filled, else\r
- * the rect is mitered stroked based on strokeWidth. If\r
- * strokeWidth == 0, then the stroke is always a single\r
- * pixel thick.\r
- * @param matrix Optional matrix applied to the rect. Applied before\r
- * context's matrix or the paint's matrix.\r
- * The rects coords are used to access the paint (through texture matrix)\r
- */\r
- void drawRect(const GrPaint& paint,\r
- const GrRect&,\r
- GrScalar strokeWidth = -1,\r
- const GrMatrix* matrix = NULL);\r
-\r
- /**\r
- * Maps a rect of paint coordinates onto the a rect of destination\r
- * coordinates. Each rect can optionally be transformed. The srcRect\r
- * is stretched over the dstRect. The dstRect is transformed by the\r
- * context's matrix and the srcRect is transformed by the paint's matrix.\r
- * Additional optional matrices can be provided by parameters.\r
- *\r
- * @param paint describes how to color pixels.\r
- * @param dstRect the destination rect to draw.\r
- * @param srcRect rect of paint coordinates to be mapped onto dstRect\r
- * @param dstMatrix Optional matrix to transform dstRect. Applied before\r
- * context's matrix.\r
- * @param srcMatrix Optional matrix to transform srcRect Applied before\r
- * paint's matrix.\r
- */\r
- void drawRectToRect(const GrPaint& paint,\r
- const GrRect& dstRect,\r
- const GrRect& srcRect,\r
- const GrMatrix* dstMatrix = NULL,\r
- const GrMatrix* srcMatrix = NULL);\r
-\r
- /**\r
- * Tessellates and draws a path.\r
- *\r
- * @param paint describes how to color pixels.\r
- * @param path the path to draw\r
- * @param fill the path filling rule to use.\r
- * @param translate optional additional translation applied to the\r
- * path.\r
- */\r
- void drawPath(const GrPaint& paint,\r
- GrPathIter* path,\r
- GrPathFill fill,\r
- const GrPoint* translate = NULL);\r
- /**\r
- * Draws vertices with a paint.\r
- *\r
- * @param paint describes how to color pixels.\r
- * @param primitiveType primitives type to draw.\r
- * @param vertexCount number of vertices.\r
- * @param positions array of vertex positions, required.\r
- * @param texCoords optional array of texture coordinates used\r
- * to access the paint.\r
- * @param colors optional array of per-vertex colors, supercedes\r
- * the paint's color field.\r
- * @param indices optional array of indices. If NULL vertices\r
- * are drawn non-indexed.\r
- * @param indexCount if indices is non-null then this is the\r
- * number of indices.\r
- */\r
- void drawVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- int vertexCount,\r
- const GrPoint positions[],\r
- const GrPoint texs[],\r
- const GrColor colors[],\r
- const uint16_t indices[],\r
- int indexCount);\r
-\r
- /**\r
- * Similar to drawVertices but caller provides objects that convert to Gr\r
- * types. The count of vertices is given by posSrc.\r
- *\r
- * @param paint describes how to color pixels.\r
- * @param primitiveType primitives type to draw.\r
- * @param posSrc Source of vertex positions. Must implement\r
- * int count() const;\r
- * void writeValue(int i, GrPoint* point) const;\r
- * count returns the total number of vertices and\r
- * writeValue writes a vertex position to point.\r
- * @param texSrc optional, pass NULL to not use explicit tex\r
- * coords. If present provides tex coords with\r
- * method:\r
- * void writeValue(int i, GrPoint* point) const;\r
- * @param texSrc optional, pass NULL to not use per-vertex colors\r
- * If present provides colors with method:\r
- * void writeValue(int i, GrColor* point) const;\r
- * @param indices optional, pass NULL for non-indexed drawing. If\r
- * present supplies indices for indexed drawing\r
- * with following methods:\r
- * int count() const;\r
- * void writeValue(int i, uint16_t* point) const;\r
- * count returns the number of indices and\r
- * writeValue supplies each index.\r
- */\r
- template <typename POS_SRC,\r
- typename TEX_SRC,\r
- typename COL_SRC,\r
- typename IDX_SRC>\r
- void drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc,\r
- const COL_SRC* colorSrc,\r
- const IDX_SRC* idxSrc);\r
- /**\r
- * To avoid the problem of having to create a typename for NULL parameters,\r
- * these reduced versions of drawCustomVertices are provided.\r
- */\r
- template <typename POS_SRC>\r
- void drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc);\r
- template <typename POS_SRC, typename TEX_SRC>\r
- void drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc);\r
- template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>\r
- void drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc,\r
- const COL_SRC* colorSrc);\r
-\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Misc.\r
-\r
- /**\r
- * Call to ensure all drawing to the context has been issued to the\r
- * underlying 3D API.\r
- * if flushRenderTarget is true then after the call the last\r
- * rendertarget set will be current in the underlying 3D API, otherwise\r
- * it may not be. It is useful to set if the caller plans to use the 3D\r
- * context outside of Ganesh to render into the current RT.\r
- */\r
- void flush(bool flushRenderTarget);\r
-\r
- /**\r
- * Return true on success, i.e. if we could copy the specified range of\r
- * pixels from the current render-target into the buffer, converting into\r
- * the specified pixel-config.\r
- */\r
- bool readPixels(int left, int top, int width, int height,\r
- GrTexture::PixelConfig, void* buffer);\r
-\r
- /**\r
- * Copy the src pixels [buffer, stride, pixelconfig] into the current\r
- * render-target at the specified rectangle.\r
- */\r
- void writePixels(int left, int top, int width, int height,\r
- GrTexture::PixelConfig, const void* buffer, size_t stride);\r
-\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Statistics\r
-\r
- void resetStats();\r
-\r
- const GrGpu::Stats& getStats() const;\r
-\r
- void printStats() const;\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Helpers\r
-\r
- class AutoRenderTarget : ::GrNoncopyable {\r
- public:\r
- AutoRenderTarget(GrContext* context, GrRenderTarget* target) {\r
- fContext = NULL;\r
- fPrevTarget = context->getRenderTarget();\r
- if (fPrevTarget != target) {\r
- context->setRenderTarget(target);\r
- fContext = context;\r
- }\r
- }\r
- ~AutoRenderTarget() {\r
- if (fContext) {\r
- fContext->setRenderTarget(fPrevTarget);\r
- }\r
- }\r
- private:\r
- GrContext* fContext;\r
- GrRenderTarget* fPrevTarget;\r
- };\r
-\r
-\r
- ///////////////////////////////////////////////////////////////////////////\r
- // Functions intended for internal use only.\r
- GrGpu* getGpu() { return fGpu; }\r
- GrFontCache* getFontCache() { return fFontCache; }\r
- GrDrawTarget* getTextTarget(const GrPaint& paint);\r
- void flushText();\r
- const GrIndexBuffer* getQuadIndexBuffer() const;\r
-\r
-private:\r
- // used to keep track of when we need to flush the draw buffer\r
- enum DrawCategory {\r
- kBuffered_DrawCategory, // last draw was inserted in draw buffer\r
- kUnbuffered_DrawCategory, // last draw was not inserted in the draw buffer\r
- kText_DrawCategory // text context was last to draw\r
- };\r
- DrawCategory fLastDrawCategory;\r
-\r
- GrGpu* fGpu;\r
- GrTextureCache* fTextureCache;\r
- GrFontCache* fFontCache;\r
- GrPathRenderer* fPathRenderer;\r
-\r
- GrVertexBufferAllocPool* fDrawBufferVBAllocPool;\r
- GrIndexBufferAllocPool* fDrawBufferIBAllocPool;\r
- GrInOrderDrawBuffer* fDrawBuffer;\r
-\r
- GrContext(GrGpu* gpu);\r
- void flushDrawBuffer();\r
-\r
- static void SetPaint(const GrPaint& paint, GrDrawTarget* target);\r
-\r
- bool finalizeTextureKey(GrTextureKey*, const GrSamplerState&) const;\r
- \r
- GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);\r
-\r
- void drawClipIntoStencil();\r
-};\r
-\r
-/**\r
- * Save/restore the view-matrix in the context.\r
- */\r
-class GrAutoMatrix : GrNoncopyable {\r
-public:\r
- GrAutoMatrix(GrContext* ctx) : fContext(ctx) {\r
- fMatrix = ctx->getMatrix();\r
- }\r
- GrAutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) {\r
- fMatrix = ctx->getMatrix();\r
- ctx->setMatrix(matrix);\r
- }\r
- ~GrAutoMatrix() {\r
- fContext->setMatrix(fMatrix);\r
- }\r
-\r
-private:\r
- GrContext* fContext;\r
- GrMatrix fMatrix;\r
-};\r
-\r
-#endif\r
-\r
-#include "GrContext_impl.h"\r
+/*
+ Copyright 2010 Google Inc.
+
+ 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 GrContext_DEFINED
+#define GrContext_DEFINED
+
+#include "GrClip.h"
+#include "GrGpu.h"
+#include "GrTextureCache.h"
+#include "GrPaint.h"
+
+class GrFontCache;
+class GrPathIter;
+class GrVertexBufferAllocPool;
+class GrIndexBufferAllocPool;
+class GrInOrderDrawBuffer;
+class GrPathRenderer;
+
+class GrContext : public GrRefCnt {
+public:
+ /**
+ * Creates a GrContext from within a 3D context.
+ */
+ static GrContext* Create(GrGpu::Engine engine,
+ GrGpu::Platform3DContext context3D);
+
+ /**
+ * Helper to create a opengl-shader based context
+ */
+ static GrContext* CreateGLShaderContext();
+
+ 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();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Textures
+
+ /**
+ * Abandons all textures. Call this if you have lost the associated GPU
+ * context, and thus internal texture references/IDs are now invalid.
+ */
+ void abandonAllTextures();
+
+ /**
+ * Search for an entry with the same Key. If found, "lock" it and return it.
+ * If not found, return null.
+ */
+ GrTextureEntry* findAndLockTexture(GrTextureKey*,
+ const GrSamplerState&);
+
+
+ /**
+ * Create a new entry, based on the specified key and texture, and return
+ * its "locked" entry.
+ *
+ * Ownership of the texture is transferred to the Entry, which will unref()
+ * it when we are purged or deleted.
+ */
+ GrTextureEntry* createAndLockTexture(GrTextureKey* key,
+ const GrSamplerState&,
+ const GrGpu::TextureDesc&,
+ void* srcData, size_t rowBytes);
+
+ /**
+ * When done with an entry, call unlockTexture(entry) on it, which returns
+ * it to the cache, where it may be purged.
+ */
+ void unlockTexture(GrTextureEntry* entry);
+
+ /**
+ * Removes an texture from the cache. This prevents the texture from
+ * being found by a subsequent findAndLockTexture() until it is
+ * reattached. The entry still counts against the cache's budget and should
+ * be reattached when exclusive access is no longer needed.
+ */
+ void detachCachedTexture(GrTextureEntry*);
+
+ /**
+ * Reattaches a texture to the cache and unlocks it. Allows it to be found
+ * by a subsequent findAndLock or be purged (provided its lock count is
+ * now 0.)
+ */
+ void reattachAndUnlockCachedTexture(GrTextureEntry*);
+
+ /**
+ * Creates a texture that is outside the cache. Does not count against
+ * cache's budget.
+ */
+ GrTexture* createUncachedTexture(const GrGpu::TextureDesc&,
+ 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);
+
+ /**
+ * 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 getMaxTextureDimension();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Render targets
+
+ /**
+ * Wraps an externally-created rendertarget in a GrRenderTarget.
+ * @param platformRenderTarget 3D API-specific render target identifier
+ * e.g. in GL platforamRenderTarget is an FBO
+ * id.
+ * @param stencilBits the number of stencil bits that the render
+ * target has.
+ * @param width width of the render target.
+ * @param height height of the render target.
+ */
+ GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,
+ int stencilBits,
+ int width, int height);
+
+ /**
+ * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
+ * viewport state from the underlying 3D API and wraps it in a
+ * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the
+ * underlying object in its destructor and it is up to caller to guarantee
+ * that it remains valid while the GrRenderTarget is used.
+ *
+ * @return the newly created GrRenderTarget
+ */
+ GrRenderTarget* createRenderTargetFrom3DApiState() {
+ return fGpu->createRenderTargetFrom3DApiState();
+ }
+
+ /**
+ * 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();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // 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 { return fGpu->getClip(); }
+
+ /**
+ * 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
+
+ /**
+ * Erase the entire render target, ignoring any clips
+ */
+ void eraseColor(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);
+
+ /**
+ * Tessellates and 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,
+ GrPathIter* 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);
+
+ /**
+ * Similar to drawVertices but caller provides objects that convert to Gr
+ * types. The count of vertices is given by posSrc.
+ *
+ * @param paint describes how to color pixels.
+ * @param primitiveType primitives type to draw.
+ * @param posSrc Source of vertex positions. Must implement
+ * int count() const;
+ * void writeValue(int i, GrPoint* point) const;
+ * count returns the total number of vertices and
+ * writeValue writes a vertex position to point.
+ * @param texSrc optional, pass NULL to not use explicit tex
+ * coords. If present provides tex coords with
+ * method:
+ * void writeValue(int i, GrPoint* point) const;
+ * @param texSrc optional, pass NULL to not use per-vertex colors
+ * If present provides colors with method:
+ * void writeValue(int i, GrColor* point) const;
+ * @param indices optional, pass NULL for non-indexed drawing. If
+ * present supplies indices for indexed drawing
+ * with following methods:
+ * int count() const;
+ * void writeValue(int i, uint16_t* point) const;
+ * count returns the number of indices and
+ * writeValue supplies each index.
+ */
+ template <typename POS_SRC,
+ typename TEX_SRC,
+ typename COL_SRC,
+ typename IDX_SRC>
+ void drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc,
+ const COL_SRC* colorSrc,
+ const IDX_SRC* idxSrc);
+ /**
+ * To avoid the problem of having to create a typename for NULL parameters,
+ * these reduced versions of drawCustomVertices are provided.
+ */
+ template <typename POS_SRC>
+ void drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc);
+ template <typename POS_SRC, typename TEX_SRC>
+ void drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc);
+ template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>
+ void drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc,
+ const COL_SRC* colorSrc);
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Misc.
+
+ /**
+ * Call to ensure all drawing to the context has been issued to the
+ * underlying 3D API.
+ * if flushRenderTarget is true then after the call the last
+ * rendertarget set will be current in the underlying 3D API, otherwise
+ * it may not be. It is useful to set if the caller plans to use the 3D
+ * context outside of Ganesh to render into the current RT.
+ */
+ void flush(bool flushRenderTarget);
+
+ /**
+ * Return true on success, i.e. if we could copy the specified range of
+ * pixels from the current render-target into the buffer, converting into
+ * the specified pixel-config.
+ */
+ bool readPixels(int left, int top, int width, int height,
+ GrTexture::PixelConfig, void* buffer);
+
+ /**
+ * Copy the src pixels [buffer, stride, pixelconfig] into the current
+ * render-target at the specified rectangle.
+ */
+ void writePixels(int left, int top, int width, int height,
+ GrTexture::PixelConfig, const void* buffer, size_t stride);
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Statistics
+
+ void resetStats();
+
+ const GrGpu::Stats& getStats() const;
+
+ void printStats() const;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // 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; }
+ GrFontCache* getFontCache() { return fFontCache; }
+ GrDrawTarget* getTextTarget(const GrPaint& paint);
+ void flushText();
+ const GrIndexBuffer* getQuadIndexBuffer() const;
+
+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;
+ GrTextureCache* fTextureCache;
+ GrFontCache* fFontCache;
+ GrPathRenderer* fPathRenderer;
+
+ GrVertexBufferAllocPool* fDrawBufferVBAllocPool;
+ GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
+ GrInOrderDrawBuffer* fDrawBuffer;
+
+ GrContext(GrGpu* gpu);
+ void flushDrawBuffer();
+
+ static void SetPaint(const GrPaint& paint, GrDrawTarget* target);
+
+ bool finalizeTextureKey(GrTextureKey*, const GrSamplerState&) const;
+
+ GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
+
+ void drawClipIntoStencil();
+};
+
+/**
+ * Save/restore the view-matrix in the context.
+ */
+class GrAutoMatrix : GrNoncopyable {
+public:
+ GrAutoMatrix(GrContext* ctx) : fContext(ctx) {
+ fMatrix = ctx->getMatrix();
+ }
+ GrAutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) {
+ fMatrix = ctx->getMatrix();
+ ctx->setMatrix(matrix);
+ }
+ ~GrAutoMatrix() {
+ fContext->setMatrix(fMatrix);
+ }
+
+private:
+ GrContext* fContext;
+ GrMatrix fMatrix;
+};
+
+#endif
+
+#include "GrContext_impl.h"
-/*\r
- Copyright 2011 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#ifndef GrContext_impl_DEFINED\r
-#define GrContext_impl_DEFINED\r
-\r
-template <typename POS_SRC, typename TEX_SRC,\r
- typename COL_SRC, typename IDX_SRC>\r
-inline void GrContext::drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc,\r
- const COL_SRC* colorSrc,\r
- const IDX_SRC* idxSrc) {\r
-\r
- GrVertexLayout layout = 0;\r
-\r
- GrDrawTarget::AutoReleaseGeometry geo;\r
-\r
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-\r
- if (NULL != paint.getTexture()) {\r
- if (NULL != texCoordSrc) {\r
- layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);\r
- } else {\r
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);\r
- }\r
- }\r
-\r
- if (NULL != colorSrc) {\r
- layout |= GrDrawTarget::kColor_VertexLayoutBit;\r
- }\r
-\r
- int vertexCount = posSrc.count();\r
- int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0;\r
-\r
- if (!geo.set(target, layout, vertexCount, indexCount)) {\r
- GrPrintf("Failed to get space for vertices!");\r
- return;\r
- }\r
-\r
- int texOffsets[GrDrawTarget::kMaxTexCoords];\r
- int colorOffset;\r
- int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,\r
- texOffsets,\r
- &colorOffset);\r
- void* curVertex = geo.vertices();\r
-\r
- for (int i = 0; i < vertexCount; ++i) {\r
- posSrc.writeValue(i, (GrPoint*)curVertex);\r
-\r
- if (texOffsets[0] > 0) {\r
- texCoordSrc->writeValue(i, (GrPoint*)((intptr_t)curVertex + texOffsets[0]));\r
- }\r
- if (colorOffset > 0) {\r
- colorSrc->writeValue(i, (GrColor*)((intptr_t)curVertex + colorOffset));\r
- }\r
- curVertex = (void*)((intptr_t)curVertex + vsize);\r
- }\r
-\r
- uint16_t* indices = (uint16_t*) geo.indices();\r
- for (int i = 0; i < indexCount; ++i) {\r
- idxSrc->writeValue(i, indices + i);\r
- }\r
-\r
- if (NULL == idxSrc) {\r
- target->drawNonIndexed(primitiveType, 0, vertexCount);\r
- } else {\r
- target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);\r
- }\r
-}\r
-\r
-class GrNullTexCoordSource {\r
-public:\r
- void writeValue(int i, GrPoint* dstCoord) const { GrAssert(false); }\r
-};\r
-\r
-class GrNullColorSource {\r
-public:\r
- void writeValue(int i, GrColor* dstColor) const { GrAssert(false); }\r
-};\r
-\r
-class GrNullIndexSource {\r
-public:\r
- void writeValue(int i, uint16_t* dstIndex) const { GrAssert(false); }\r
- int count() const { GrAssert(false); return 0; }\r
-};\r
-\r
-template <typename POS_SRC>\r
-inline void GrContext::drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc) {\r
- this->drawCustomVertices<POS_SRC,\r
- GrNullTexCoordSource,\r
- GrNullColorSource,\r
- GrNullIndexSource>(paint, primitiveType, posSrc,\r
- NULL, NULL, NULL);\r
-}\r
-\r
-template <typename POS_SRC, typename TEX_SRC>\r
-inline void GrContext::drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc) {\r
- this->drawCustomVertices<POS_SRC, TEX_SRC,\r
- GrNullColorSource,\r
- GrNullIndexSource>(paint, primitiveType, posSrc,\r
- texCoordSrc, NULL, NULL);\r
-}\r
-\r
-template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>\r
-inline void GrContext::drawCustomVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- const POS_SRC& posSrc,\r
- const TEX_SRC* texCoordSrc,\r
- const COL_SRC* colorSrc) {\r
- drawCustomVertices<POS_SRC, TEX_SRC, COL_SRC,\r
- GrNullIndexSource>(paint, primitiveType, posSrc, \r
- texCoordSrc, colorSrc, NULL);\r
-}\r
-\r
-#endif\r
+/*
+ Copyright 2011 Google Inc.
+
+ 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 GrContext_impl_DEFINED
+#define GrContext_impl_DEFINED
+
+template <typename POS_SRC, typename TEX_SRC,
+ typename COL_SRC, typename IDX_SRC>
+inline void GrContext::drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc,
+ const COL_SRC* colorSrc,
+ const IDX_SRC* idxSrc) {
+
+ GrVertexLayout layout = 0;
+
+ GrDrawTarget::AutoReleaseGeometry geo;
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ if (NULL != paint.getTexture()) {
+ if (NULL != texCoordSrc) {
+ layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
+ } else {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
+ }
+ }
+
+ if (NULL != colorSrc) {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ }
+
+ int vertexCount = posSrc.count();
+ int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0;
+
+ if (!geo.set(target, layout, vertexCount, indexCount)) {
+ GrPrintf("Failed to get space for vertices!");
+ return;
+ }
+
+ int texOffsets[GrDrawTarget::kMaxTexCoords];
+ int colorOffset;
+ int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
+ texOffsets,
+ &colorOffset);
+ void* curVertex = geo.vertices();
+
+ for (int i = 0; i < vertexCount; ++i) {
+ posSrc.writeValue(i, (GrPoint*)curVertex);
+
+ if (texOffsets[0] > 0) {
+ texCoordSrc->writeValue(i, (GrPoint*)((intptr_t)curVertex + texOffsets[0]));
+ }
+ if (colorOffset > 0) {
+ colorSrc->writeValue(i, (GrColor*)((intptr_t)curVertex + colorOffset));
+ }
+ curVertex = (void*)((intptr_t)curVertex + vsize);
+ }
+
+ uint16_t* indices = (uint16_t*) geo.indices();
+ for (int i = 0; i < indexCount; ++i) {
+ idxSrc->writeValue(i, indices + i);
+ }
+
+ if (NULL == idxSrc) {
+ target->drawNonIndexed(primitiveType, 0, vertexCount);
+ } else {
+ target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+ }
+}
+
+class GrNullTexCoordSource {
+public:
+ void writeValue(int i, GrPoint* dstCoord) const { GrAssert(false); }
+};
+
+class GrNullColorSource {
+public:
+ void writeValue(int i, GrColor* dstColor) const { GrAssert(false); }
+};
+
+class GrNullIndexSource {
+public:
+ void writeValue(int i, uint16_t* dstIndex) const { GrAssert(false); }
+ int count() const { GrAssert(false); return 0; }
+};
+
+template <typename POS_SRC>
+inline void GrContext::drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc) {
+ this->drawCustomVertices<POS_SRC,
+ GrNullTexCoordSource,
+ GrNullColorSource,
+ GrNullIndexSource>(paint, primitiveType, posSrc,
+ NULL, NULL, NULL);
+}
+
+template <typename POS_SRC, typename TEX_SRC>
+inline void GrContext::drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc) {
+ this->drawCustomVertices<POS_SRC, TEX_SRC,
+ GrNullColorSource,
+ GrNullIndexSource>(paint, primitiveType, posSrc,
+ texCoordSrc, NULL, NULL);
+}
+
+template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>
+inline void GrContext::drawCustomVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ const POS_SRC& posSrc,
+ const TEX_SRC* texCoordSrc,
+ const COL_SRC* colorSrc) {
+ drawCustomVertices<POS_SRC, TEX_SRC, COL_SRC,
+ GrNullIndexSource>(paint, primitiveType, posSrc,
+ texCoordSrc, colorSrc, NULL);
+}
+
+#endif
* @param stage the stage of the sampler to set
* @param matrix the matrix to concat
*/
- void preConcatSamplerMatrix(int stage, const GrMatrix& matrix) {\r
- GrAssert(stage >= 0 && stage < kNumStages);\r
- fCurrDrawState.fSamplerStates[stage].preConcatMatrix(matrix);\r
+ void preConcatSamplerMatrix(int stage, const GrMatrix& matrix) {
+ GrAssert(stage >= 0 && stage < kNumStages);
+ fCurrDrawState.fSamplerStates[stage].preConcatMatrix(matrix);
}
/**
-/*\r
- Copyright 2011 Google Inc.\r
- \r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
- \r
- http://www.apache.org/licenses/LICENSE-2.0\r
- \r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#ifndef GrGeometryBuffer_DEFINED\r
-#define GrGeometryBuffer_DEFINED\r
-\r
-#include "GrRefCnt.h"\r
-\r
-/**\r
- * Parent class for vertex and index buffers\r
- */\r
-class GrGeometryBuffer : public GrRefCnt {\r
-public:\r
- virtual ~GrGeometryBuffer() {}\r
- \r
- /**\r
- * Retrieves the size of the buffer\r
- *\r
- * @return the size of the buffer in bytes\r
- */\r
- size_t size() const { return fSizeInBytes; }\r
- \r
- /**\r
- *Retrieves whether the buffer was created with the dynamic flag\r
- *\r
- * @return true if the buffer was created with the dynamic flag\r
- */\r
- bool dynamic() const { return fDynamic; }\r
- \r
- /**\r
- * Indicates that GPU context in which this veretx buffer was created is \r
- * destroyed and that Ganesh should not attempt to free the buffer in the\r
- * underlying API.\r
- */\r
- virtual void abandon() = 0;\r
- \r
- /**\r
- * Locks the buffer to be written by the CPU.\r
- * \r
- * The previous content of the buffer is invalidated. It is an error\r
- * to draw from the buffer while it is locked. It is an error to call lock\r
- * on an already locked buffer.\r
- * \r
- * @return a pointer to the data or NULL if the lock fails.\r
- */\r
- virtual void* lock() = 0;\r
- \r
- /**\r
- * Returns the same ptr that lock() returned at time of lock or NULL if the\r
- * is not locked.\r
- *\r
- * @return ptr to locked buffer data or undefined if buffer is not locked.\r
- */\r
- virtual void* lockPtr() const = 0;\r
- \r
- /** \r
- * Unlocks the buffer. \r
- * \r
- * The pointer returned by the previous lock call will no longer be valid.\r
- */\r
- virtual void unlock() = 0;\r
- \r
- /** \r
- Queries whether the buffer has been locked.\r
- \r
- @return true if the buffer is locked, false otherwise.\r
- */\r
- virtual bool isLocked() const = 0;\r
- \r
- /**\r
- * Updates the buffer data. \r
- * \r
- * The size of the buffer will be preserved. The src data will be \r
- * placed at the begining of the buffer and any remaining contents will\r
- * be undefined.\r
- * \r
- * @return returns true if the update succeeds, false otherwise.\r
- */\r
- virtual bool updateData(const void* src, size_t srcSizeInBytes) = 0;\r
- \r
- /**\r
- * Updates a portion of the buffer data. \r
- * \r
- * The contents of the buffer outside the update region are preserved.\r
- * \r
- * @return returns true if the update succeeds, false otherwise.\r
- */\r
- virtual bool updateSubData(const void* src, \r
- size_t srcSizeInBytes, \r
- size_t offset) = 0;\r
-protected:\r
- GrGeometryBuffer(size_t sizeInBytes, bool dynamic) : \r
- fSizeInBytes(sizeInBytes),\r
- fDynamic(dynamic) {}\r
-\r
-private:\r
- size_t fSizeInBytes;\r
- bool fDynamic;\r
-\r
- typedef GrRefCnt INHERITED;\r
-};\r
-\r
-#endif\r
+/*
+ Copyright 2011 Google Inc.
+
+ 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 GrGeometryBuffer_DEFINED
+#define GrGeometryBuffer_DEFINED
+
+#include "GrRefCnt.h"
+
+/**
+ * Parent class for vertex and index buffers
+ */
+class GrGeometryBuffer : public GrRefCnt {
+public:
+ virtual ~GrGeometryBuffer() {}
+
+ /**
+ * Retrieves the size of the buffer
+ *
+ * @return the size of the buffer in bytes
+ */
+ size_t size() const { return fSizeInBytes; }
+
+ /**
+ *Retrieves whether the buffer was created with the dynamic flag
+ *
+ * @return true if the buffer was created with the dynamic flag
+ */
+ bool dynamic() const { return fDynamic; }
+
+ /**
+ * Indicates that GPU context in which this veretx buffer was created is
+ * destroyed and that Ganesh should not attempt to free the buffer in the
+ * underlying API.
+ */
+ virtual void abandon() = 0;
+
+ /**
+ * Locks the buffer to be written by the CPU.
+ *
+ * The previous content of the buffer is invalidated. It is an error
+ * to draw from the buffer while it is locked. It is an error to call lock
+ * on an already locked buffer.
+ *
+ * @return a pointer to the data or NULL if the lock fails.
+ */
+ virtual void* lock() = 0;
+
+ /**
+ * Returns the same ptr that lock() returned at time of lock or NULL if the
+ * is not locked.
+ *
+ * @return ptr to locked buffer data or undefined if buffer is not locked.
+ */
+ virtual void* lockPtr() const = 0;
+
+ /**
+ * Unlocks the buffer.
+ *
+ * The pointer returned by the previous lock call will no longer be valid.
+ */
+ virtual void unlock() = 0;
+
+ /**
+ Queries whether the buffer has been locked.
+
+ @return true if the buffer is locked, false otherwise.
+ */
+ virtual bool isLocked() const = 0;
+
+ /**
+ * Updates the buffer data.
+ *
+ * The size of the buffer will be preserved. The src data will be
+ * placed at the begining of the buffer and any remaining contents will
+ * be undefined.
+ *
+ * @return returns true if the update succeeds, false otherwise.
+ */
+ virtual bool updateData(const void* src, size_t srcSizeInBytes) = 0;
+
+ /**
+ * Updates a portion of the buffer data.
+ *
+ * The contents of the buffer outside the update region are preserved.
+ *
+ * @return returns true if the update succeeds, false otherwise.
+ */
+ virtual bool updateSubData(const void* src,
+ size_t srcSizeInBytes,
+ size_t offset) = 0;
+protected:
+ GrGeometryBuffer(size_t sizeInBytes, bool dynamic) :
+ fSizeInBytes(sizeInBytes),
+ fDynamic(dynamic) {}
+
+private:
+ size_t fSizeInBytes;
+ bool fDynamic;
+
+ typedef GrRefCnt INHERITED;
+};
+
+#endif
-/*\r
- Copyright 2011 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#ifndef GrPaint_DEFINED\r
-#define GrPaint_DEFINED\r
-\r
-#include "GrTexture.h"\r
-#include "GrColor.h"\r
-#include "GrSamplerState.h"\r
-\r
-/**\r
- * The paint describes how pixels are colored when the context draws to\r
- * them.\r
- */\r
-class GrPaint {\r
-public:\r
-\r
- // All the paint fields are public except texture (it's ref-counted)\r
- GrBlendCoeff fSrcBlendCoeff;\r
- GrBlendCoeff fDstBlendCoeff;\r
- bool fAntiAlias;\r
- bool fDither;\r
-\r
- GrColor fColor;\r
-\r
- GrSamplerState fSampler;\r
-\r
- void setTexture(GrTexture* texture) {\r
- GrSafeRef(texture);\r
- GrSafeUnref(fTexture);\r
- fTexture = texture;\r
- }\r
-\r
- GrTexture* getTexture() const { return fTexture; }\r
-\r
- // uninitialized\r
- GrPaint() {\r
- fTexture = NULL;\r
- }\r
-\r
- GrPaint(const GrPaint& paint) {\r
- fSrcBlendCoeff = paint.fSrcBlendCoeff;\r
- fDstBlendCoeff = paint.fDstBlendCoeff;\r
- fAntiAlias = paint.fAntiAlias;\r
- fDither = paint.fDither;\r
-\r
- fColor = paint.fColor;\r
-\r
- fSampler = paint.fSampler;\r
- fTexture = paint.fTexture;\r
- GrSafeRef(fTexture);\r
- }\r
-\r
- ~GrPaint() {\r
- GrSafeUnref(fTexture);\r
- }\r
-\r
- // sets paint to src-over, solid white, no texture\r
- void reset() {\r
- resetBlend();\r
- resetOptions();\r
- resetColor();\r
- resetTexture();\r
- }\r
-\r
-private:\r
- GrTexture* fTexture;\r
-\r
- void resetBlend() {\r
- fSrcBlendCoeff = kOne_BlendCoeff;\r
- fDstBlendCoeff = kZero_BlendCoeff;\r
- }\r
-\r
- void resetOptions() {\r
- fAntiAlias = false;\r
- fDither = false;\r
- }\r
-\r
- void resetColor() {\r
- fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);\r
- }\r
-\r
- void resetTexture() {\r
- setTexture(NULL);\r
- fSampler.setClampNoFilter();\r
- }\r
-\r
-};\r
-\r
-#endif\r
+/*
+ Copyright 2011 Google Inc.
+
+ 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 GrPaint_DEFINED
+#define GrPaint_DEFINED
+
+#include "GrTexture.h"
+#include "GrColor.h"
+#include "GrSamplerState.h"
+
+/**
+ * The paint describes how pixels are colored when the context draws to
+ * them.
+ */
+class GrPaint {
+public:
+
+ // All the paint fields are public except texture (it's ref-counted)
+ GrBlendCoeff fSrcBlendCoeff;
+ GrBlendCoeff fDstBlendCoeff;
+ bool fAntiAlias;
+ bool fDither;
+
+ GrColor fColor;
+
+ GrSamplerState fSampler;
+
+ void setTexture(GrTexture* texture) {
+ GrSafeRef(texture);
+ GrSafeUnref(fTexture);
+ fTexture = texture;
+ }
+
+ GrTexture* getTexture() const { return fTexture; }
+
+ // uninitialized
+ GrPaint() {
+ fTexture = NULL;
+ }
+
+ GrPaint(const GrPaint& paint) {
+ fSrcBlendCoeff = paint.fSrcBlendCoeff;
+ fDstBlendCoeff = paint.fDstBlendCoeff;
+ fAntiAlias = paint.fAntiAlias;
+ fDither = paint.fDither;
+
+ fColor = paint.fColor;
+
+ fSampler = paint.fSampler;
+ fTexture = paint.fTexture;
+ GrSafeRef(fTexture);
+ }
+
+ ~GrPaint() {
+ GrSafeUnref(fTexture);
+ }
+
+ // sets paint to src-over, solid white, no texture
+ void reset() {
+ resetBlend();
+ resetOptions();
+ resetColor();
+ resetTexture();
+ }
+
+private:
+ GrTexture* fTexture;
+
+ void resetBlend() {
+ fSrcBlendCoeff = kOne_BlendCoeff;
+ fDstBlendCoeff = kZero_BlendCoeff;
+ }
+
+ void resetOptions() {
+ fAntiAlias = false;
+ fDither = false;
+ }
+
+ void resetColor() {
+ fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
+ }
+
+ void resetTexture() {
+ setTexture(NULL);
+ fSampler.setClampNoFilter();
+ }
+
+};
+
+#endif
-/*\r
- Copyright 2010 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#include "GrContext.h"\r
-#include "GrTypes.h"\r
-#include "GrTextureCache.h"\r
-#include "GrTextStrike.h"\r
-#include "GrMemory.h"\r
-#include "GrPathIter.h"\r
-#include "GrClipIterator.h"\r
-#include "GrIndexBuffer.h"\r
-#include "GrInOrderDrawBuffer.h"\r
-#include "GrBufferAllocPool.h"\r
-#include "GrPathRenderer.h"\r
-\r
-#define DEFER_TEXT_RENDERING 1\r
-\r
-#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)\r
-\r
-static const size_t MAX_TEXTURE_CACHE_COUNT = 128;\r
-static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;\r
-\r
-static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;\r
-static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;\r
-\r
-// We are currently only batching Text and drawRectToRect, both\r
-// of which use the quad index buffer.\r
-static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;\r
-static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;\r
-\r
-GrContext* GrContext::Create(GrGpu::Engine engine,\r
- GrGpu::Platform3DContext context3D) {\r
- GrContext* ctx = NULL;\r
- GrGpu* fGpu = GrGpu::Create(engine, context3D);\r
- if (NULL != fGpu) {\r
- ctx = new GrContext(fGpu);\r
- fGpu->unref();\r
- }\r
- return ctx;\r
-}\r
-\r
-GrContext* GrContext::CreateGLShaderContext() {\r
- return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);\r
-}\r
-\r
-GrContext::~GrContext() {\r
- fGpu->unref();\r
- delete fTextureCache;\r
- delete fFontCache;\r
- delete fDrawBuffer;\r
- delete fDrawBufferVBAllocPool;\r
- delete fDrawBufferVBAllocPool;\r
- delete fPathRenderer;\r
-}\r
-\r
-void GrContext::abandonAllTextures() {\r
- fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);\r
- fFontCache->abandonAll();\r
-}\r
-\r
-GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,\r
- const GrSamplerState& sampler) {\r
- finalizeTextureKey(key, sampler);\r
- return fTextureCache->findAndLock(*key);\r
-}\r
-\r
-static void stretchImage(void* dst,\r
- int dstW,\r
- int dstH,\r
- void* src,\r
- int srcW,\r
- int srcH,\r
- int bpp) {\r
- GrFixed dx = (srcW << 16) / dstW;\r
- GrFixed dy = (srcH << 16) / dstH;\r
-\r
- GrFixed y = dy >> 1;\r
-\r
- int dstXLimit = dstW*bpp;\r
- for (int j = 0; j < dstH; ++j) {\r
- GrFixed x = dx >> 1;\r
- void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;\r
- void* dstRow = (uint8_t*)dst + j*dstW*bpp;\r
- for (int i = 0; i < dstXLimit; i += bpp) {\r
- memcpy((uint8_t*) dstRow + i,\r
- (uint8_t*) srcRow + (x>>16)*bpp,\r
- bpp);\r
- x += dx;\r
- }\r
- y += dy;\r
- }\r
-}\r
-\r
-GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,\r
- const GrSamplerState& sampler,\r
- const GrGpu::TextureDesc& desc,\r
- void* srcData, size_t rowBytes) {\r
- GrAssert(key->width() == desc.fWidth);\r
- GrAssert(key->height() == desc.fHeight);\r
-\r
-#if GR_DUMP_TEXTURE_UPLOAD\r
- GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);\r
-#endif\r
-\r
- GrTextureEntry* entry = NULL;\r
- bool special = finalizeTextureKey(key, sampler);\r
- if (special) {\r
- GrTextureEntry* clampEntry;\r
- GrTextureKey clampKey(*key);\r
- clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());\r
-\r
- if (NULL == clampEntry) {\r
- clampEntry = createAndLockTexture(&clampKey,\r
- GrSamplerState::ClampNoFilter(),\r
- desc, srcData, rowBytes);\r
- GrAssert(NULL != clampEntry);\r
- if (NULL == clampEntry) {\r
- return NULL;\r
- }\r
- }\r
- GrGpu::TextureDesc rtDesc = desc;\r
- rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |\r
- GrGpu::kNoPathRendering_TextureFlag;\r
- rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,\r
- fGpu->minRenderTargetWidth()));\r
- rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,\r
- fGpu->minRenderTargetHeight()));\r
-\r
- GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);\r
-\r
- if (NULL != texture) {\r
- GrDrawTarget::AutoStateRestore asr(fGpu);\r
- fGpu->setRenderTarget(texture->asRenderTarget());\r
- fGpu->setTexture(0, clampEntry->texture());\r
- fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);\r
- fGpu->setViewMatrix(GrMatrix::I());\r
- fGpu->setAlpha(0xff);\r
- fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);\r
- fGpu->disableState(GrDrawTarget::kDither_StateBit |\r
- GrDrawTarget::kClip_StateBit |\r
- GrDrawTarget::kAntialias_StateBit);\r
- GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,\r
- GrSamplerState::kClamp_WrapMode,\r
- sampler.isFilter());\r
- fGpu->setSamplerState(0, stretchSampler);\r
-\r
- static const GrVertexLayout layout =\r
- GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);\r
- GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);\r
-\r
- if (arg.succeeded()) {\r
- GrPoint* verts = (GrPoint*) arg.vertices();\r
- verts[0].setIRectFan(0, 0,\r
- texture->width(),\r
- texture->height(),\r
- 2*sizeof(GrPoint));\r
- verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));\r
- fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,\r
- 0, 4);\r
- entry = fTextureCache->createAndLock(*key, texture);\r
- }\r
- texture->removeRenderTarget();\r
- } else {\r
- // TODO: Our CPU stretch doesn't filter. But we create separate\r
- // stretched textures when the sampler state is either filtered or\r
- // not. Either implement filtered stretch blit on CPU or just create\r
- // one when FBO case fails.\r
-\r
- rtDesc.fFlags = 0;\r
- // no longer need to clamp at min RT size.\r
- rtDesc.fWidth = GrNextPow2(desc.fWidth);\r
- rtDesc.fHeight = GrNextPow2(desc.fHeight);\r
- int bpp = GrTexture::BytesPerPixel(desc.fFormat);\r
- GrAutoSMalloc<128*128*4> stretchedPixels(bpp *\r
- rtDesc.fWidth *\r
- rtDesc.fHeight);\r
- stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,\r
- srcData, desc.fWidth, desc.fHeight, bpp);\r
-\r
- size_t stretchedRowBytes = rtDesc.fWidth * bpp;\r
-\r
- GrTexture* texture = fGpu->createTexture(rtDesc,\r
- stretchedPixels.get(),\r
- stretchedRowBytes);\r
- GrAssert(NULL != texture);\r
- entry = fTextureCache->createAndLock(*key, texture);\r
- }\r
- fTextureCache->unlock(clampEntry);\r
-\r
- } else {\r
- GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);\r
- if (NULL != texture) {\r
- entry = fTextureCache->createAndLock(*key, texture);\r
- } else {\r
- entry = NULL;\r
- }\r
- }\r
- return entry;\r
-}\r
-\r
-void GrContext::unlockTexture(GrTextureEntry* entry) {\r
- fTextureCache->unlock(entry);\r
-}\r
-\r
-void GrContext::detachCachedTexture(GrTextureEntry* entry) {\r
- fTextureCache->detach(entry);\r
-}\r
-\r
-void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {\r
- fTextureCache->reattachAndUnlock(entry);\r
-}\r
-\r
-GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,\r
- void* srcData,\r
- size_t rowBytes) {\r
- return fGpu->createTexture(desc, srcData, rowBytes);\r
-}\r
-\r
-void GrContext::getTextureCacheLimits(int* maxTextures,\r
- size_t* maxTextureBytes) const {\r
- fTextureCache->getLimits(maxTextures, maxTextureBytes);\r
-}\r
-\r
-void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {\r
- fTextureCache->setLimits(maxTextures, maxTextureBytes);\r
-}\r
-\r
-int GrContext::getMaxTextureDimension() {\r
- return fGpu->maxTextureDimension();\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-\r
-GrRenderTarget* GrContext::createPlatformRenderTarget(\r
- intptr_t platformRenderTarget,\r
- int stencilBits,\r
- int width, int height) {\r
- return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,\r
- width, height);\r
-}\r
-\r
-bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,\r
- int width, int height) {\r
- if (!fGpu->supports8BitPalette()) {\r
- return false;\r
- }\r
-\r
-\r
- bool isPow2 = GrIsPow2(width) && GrIsPow2(height);\r
-\r
- if (!isPow2) {\r
- if (!fGpu->npotTextureSupport()) {\r
- return false;\r
- }\r
-\r
- bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||\r
- sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;\r
- if (tiled && !fGpu->npotTextureTileSupport()) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::setClip(const GrClip& clip) {\r
- fGpu->setClip(clip);\r
- fGpu->enableState(GrDrawTarget::kClip_StateBit);\r
-}\r
-\r
-void GrContext::setClip(const GrIRect& rect) {\r
- GrClip clip;\r
- clip.setRect(rect);\r
- fGpu->setClip(clip);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::eraseColor(GrColor color) {\r
- fGpu->eraseColor(color);\r
-}\r
-\r
-void GrContext::drawPaint(const GrPaint& paint) {\r
- // set rect to be big enough to fill the space, but not super-huge, so we\r
- // don't overflow fixed-point implementations\r
- GrRect r(fGpu->getClip().getBounds());\r
- GrMatrix inverse;\r
- if (fGpu->getViewInverse(&inverse)) {\r
- inverse.mapRect(&r);\r
- } else {\r
- GrPrintf("---- fGpu->getViewInverse failed\n");\r
- }\r
- this->drawRect(paint, r);\r
-}\r
-\r
-/* create a triangle strip that strokes the specified triangle. There are 8\r
- unique vertices, but we repreat the last 2 to close up. Alternatively we\r
- could use an indices array, and then only send 8 verts, but not sure that\r
- would be faster.\r
- */\r
-static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,\r
- GrScalar width) {\r
- const GrScalar rad = GrScalarHalf(width);\r
-\r
- verts[0].set(rect.fLeft + rad, rect.fTop + rad);\r
- verts[1].set(rect.fLeft - rad, rect.fTop - rad);\r
- verts[2].set(rect.fRight - rad, rect.fTop + rad);\r
- verts[3].set(rect.fRight + rad, rect.fTop - rad);\r
- verts[4].set(rect.fRight - rad, rect.fBottom - rad);\r
- verts[5].set(rect.fRight + rad, rect.fBottom + rad);\r
- verts[6].set(rect.fLeft + rad, rect.fBottom - rad);\r
- verts[7].set(rect.fLeft - rad, rect.fBottom + rad);\r
- verts[8] = verts[0];\r
- verts[9] = verts[1];\r
-}\r
-\r
-void GrContext::drawRect(const GrPaint& paint,\r
- const GrRect& rect,\r
- GrScalar width,\r
- const GrMatrix* matrix) {\r
-\r
- bool textured = NULL != paint.getTexture();\r
-\r
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-\r
- if (width >= 0) {\r
- // TODO: consider making static vertex buffers for these cases.\r
- // Hairline could be done by just adding closing vertex to\r
- // unitSquareVertexBuffer()\r
- GrVertexLayout layout = (textured) ?\r
- GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :\r
- 0;\r
- static const int worstCaseVertCount = 10;\r
- GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);\r
-\r
- if (!geo.succeeded()) {\r
- return;\r
- }\r
-\r
- GrPrimitiveType primType;\r
- int vertCount;\r
- GrPoint* vertex = geo.positions();\r
-\r
- if (width > 0) {\r
- vertCount = 10;\r
- primType = kTriangleStrip_PrimitiveType;\r
- setStrokeRectStrip(vertex, rect, width);\r
- } else {\r
- // hairline\r
- vertCount = 5;\r
- primType = kLineStrip_PrimitiveType;\r
- vertex[0].set(rect.fLeft, rect.fTop);\r
- vertex[1].set(rect.fRight, rect.fTop);\r
- vertex[2].set(rect.fRight, rect.fBottom);\r
- vertex[3].set(rect.fLeft, rect.fBottom);\r
- vertex[4].set(rect.fLeft, rect.fTop);\r
- }\r
-\r
- GrDrawTarget::AutoViewMatrixRestore avmr;\r
- if (NULL != matrix) {\r
- avmr.set(target);\r
- target->preConcatViewMatrix(*matrix);\r
- target->preConcatSamplerMatrix(0, *matrix);\r
- }\r
-\r
- target->drawNonIndexed(primType, 0, vertCount);\r
- } else {\r
- #if GR_STATIC_RECT_VB\r
- GrVertexLayout layout = (textured) ?\r
- GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :\r
- 0;\r
- target->setVertexSourceToBuffer(layout, \r
- fGpu->getUnitSquareVertexBuffer());\r
- GrDrawTarget::AutoViewMatrixRestore avmr(target);\r
- GrMatrix m;\r
- m.setAll(rect.width(), 0, rect.fLeft,\r
- 0, rect.height(), rect.fTop,\r
- 0, 0, GrMatrix::I()[8]);\r
-\r
- if (NULL != matrix) {\r
- m.postConcat(*matrix);\r
- }\r
-\r
- target->preConcatViewMatrix(m);\r
-\r
- if (textured) {\r
- target->preConcatSamplerMatrix(0, m);\r
- }\r
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);\r
- #else\r
- target->drawSimpleRect(rect, matrix, textured ? 1 : 0);\r
- #endif\r
- }\r
-}\r
-\r
-void GrContext::drawRectToRect(const GrPaint& paint,\r
- const GrRect& dstRect,\r
- const GrRect& srcRect,\r
- const GrMatrix* dstMatrix,\r
- const GrMatrix* srcMatrix) {\r
-\r
- if (NULL == paint.getTexture()) {\r
- drawRect(paint, dstRect, -1, dstMatrix);\r
- return;\r
- }\r
- \r
- GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);\r
-\r
-#if GR_STATIC_RECT_VB\r
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-\r
- GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);\r
- GrDrawTarget::AutoViewMatrixRestore avmr(target);\r
-\r
- GrMatrix m;\r
-\r
- m.setAll(dstRect.width(), 0, dstRect.fLeft,\r
- 0, dstRect.height(), dstRect.fTop,\r
- 0, 0, GrMatrix::I()[8]);\r
- if (NULL != dstMatrix) {\r
- m.postConcat(*dstMatrix);\r
- }\r
- target->preConcatViewMatrix(m);\r
-\r
- m.setAll(srcRect.width(), 0, srcRect.fLeft,\r
- 0, srcRect.height(), srcRect.fTop,\r
- 0, 0, GrMatrix::I()[8]);\r
- if (NULL != srcMatrix) {\r
- m.postConcat(*srcMatrix);\r
- }\r
- target->preConcatSamplerMatrix(0, m);\r
-\r
- target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());\r
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);\r
-#else\r
-\r
- GrDrawTarget* target;\r
-#if BATCH_RECT_TO_RECT \r
- target = this->prepareToDraw(paint, kBuffered_DrawCategory);\r
-#else \r
- target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-#endif\r
-\r
- const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};\r
- const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};\r
- srcRects[0] = &srcRect;\r
- srcMatrices[0] = srcMatrix;\r
-\r
- target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);\r
-#endif\r
-}\r
-\r
-void GrContext::drawVertices(const GrPaint& paint,\r
- GrPrimitiveType primitiveType,\r
- int vertexCount,\r
- const GrPoint positions[],\r
- const GrPoint texCoords[],\r
- const GrColor colors[],\r
- const uint16_t indices[],\r
- int indexCount) {\r
- GrVertexLayout layout = 0;\r
- int vertexSize = sizeof(GrPoint);\r
-\r
- GrDrawTarget::AutoReleaseGeometry geo;\r
-\r
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-\r
- if (NULL != paint.getTexture()) {\r
- if (NULL == texCoords) {\r
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);\r
- } else {\r
- layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);\r
- vertexSize += sizeof(GrPoint);\r
- }\r
- }\r
-\r
- if (NULL != colors) {\r
- layout |= GrDrawTarget::kColor_VertexLayoutBit;\r
- vertexSize += sizeof(GrColor);\r
- }\r
-\r
- if (sizeof(GrPoint) != vertexSize) {\r
- if (!geo.set(target, layout, vertexCount, 0)) {\r
- GrPrintf("Failed to get space for vertices!");\r
- return;\r
- }\r
- int texOffsets[GrDrawTarget::kMaxTexCoords];\r
- int colorOffset;\r
- int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,\r
- texOffsets,\r
- &colorOffset);\r
- void* curVertex = geo.vertices();\r
-\r
- for (int i = 0; i < vertexCount; ++i) {\r
- *((GrPoint*)curVertex) = positions[i];\r
-\r
- if (texOffsets[0] > 0) {\r
- *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];\r
- }\r
- if (colorOffset > 0) {\r
- *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];\r
- }\r
- curVertex = (void*)((intptr_t)curVertex + vsize);\r
- }\r
- } else {\r
- target->setVertexSourceToArray(layout, positions, vertexCount);\r
- }\r
-\r
- if (NULL != indices) {\r
- target->setIndexSourceToArray(indices, indexCount);\r
- target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);\r
- } else {\r
- target->drawNonIndexed(primitiveType, 0, vertexCount);\r
- }\r
-}\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::drawPath(const GrPaint& paint,\r
- GrPathIter* path,\r
- GrPathFill fill,\r
- const GrPoint* translate) {\r
-\r
-\r
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-\r
- GrDrawTarget::StageBitfield enabledStages = 0;\r
- if (NULL != paint.getTexture()) {\r
- enabledStages |= 1;\r
- }\r
- fPathRenderer->drawPath(target, enabledStages, path, fill, translate);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::flush(bool flushRenderTarget) {\r
- flushDrawBuffer();\r
- if (flushRenderTarget) {\r
- fGpu->forceRenderTargetFlush();\r
- }\r
-}\r
-\r
-void GrContext::flushText() {\r
- if (kText_DrawCategory == fLastDrawCategory) {\r
- flushDrawBuffer();\r
- }\r
-}\r
-\r
-void GrContext::flushDrawBuffer() {\r
-#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING\r
- fDrawBuffer->playback(fGpu);\r
- fDrawBuffer->reset();\r
-#endif\r
-}\r
-\r
-bool GrContext::readPixels(int left, int top, int width, int height,\r
- GrTexture::PixelConfig config, void* buffer) {\r
- this->flush(true);\r
- return fGpu->readPixels(left, top, width, height, config, buffer);\r
-}\r
-\r
-void GrContext::writePixels(int left, int top, int width, int height,\r
- GrTexture::PixelConfig config, const void* buffer,\r
- size_t stride) {\r
-\r
- // TODO: when underlying api has a direct way to do this we should use it\r
- // (e.g. glDrawPixels on desktop GL).\r
-\r
- const GrGpu::TextureDesc desc = {\r
- 0, GrGpu::kNone_AALevel, width, height, config\r
- };\r
- GrTexture* texture = fGpu->createTexture(desc, buffer, stride);\r
- if (NULL == texture) {\r
- return;\r
- }\r
-\r
- this->flush(true);\r
-\r
- GrAutoUnref aur(texture);\r
- GrDrawTarget::AutoStateRestore asr(fGpu);\r
-\r
- GrMatrix matrix;\r
- matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));\r
- fGpu->setViewMatrix(matrix);\r
-\r
- fGpu->disableState(GrDrawTarget::kClip_StateBit);\r
- fGpu->setAlpha(0xFF);\r
- fGpu->setBlendFunc(kOne_BlendCoeff,\r
- kZero_BlendCoeff);\r
- fGpu->setTexture(0, texture);\r
-\r
- GrSamplerState sampler;\r
- sampler.setClampNoFilter();\r
- matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);\r
- sampler.setMatrix(matrix);\r
- fGpu->setSamplerState(0, sampler);\r
-\r
- GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);\r
- static const int VCOUNT = 4;\r
-\r
- GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);\r
- if (!geo.succeeded()) {\r
- return;\r
- }\r
- ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);\r
- fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {\r
- target->setTexture(0, paint.getTexture());\r
- target->setSamplerState(0, paint.fSampler);\r
- target->setColor(paint.fColor);\r
-\r
- if (paint.fDither) {\r
- target->enableState(GrDrawTarget::kDither_StateBit);\r
- } else {\r
- target->disableState(GrDrawTarget::kDither_StateBit);\r
- }\r
- if (paint.fAntiAlias) {\r
- target->enableState(GrDrawTarget::kAntialias_StateBit);\r
- } else {\r
- target->disableState(GrDrawTarget::kAntialias_StateBit);\r
- }\r
- target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);\r
-}\r
-\r
-GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, \r
- DrawCategory category) {\r
- if (category != fLastDrawCategory) {\r
- flushDrawBuffer();\r
- fLastDrawCategory = category;\r
- }\r
- SetPaint(paint, fGpu);\r
- GrDrawTarget* target = fGpu;\r
- switch (category) {\r
- case kText_DrawCategory:\r
-#if DEFER_TEXT_RENDERING\r
- target = fDrawBuffer;\r
- fDrawBuffer->initializeDrawStateAndClip(*fGpu);\r
-#else\r
- target = fGpu;\r
-#endif\r
- break;\r
- case kUnbuffered_DrawCategory:\r
- target = fGpu;\r
- break;\r
- case kBuffered_DrawCategory:\r
- target = fDrawBuffer;\r
- fDrawBuffer->initializeDrawStateAndClip(*fGpu);\r
- break;\r
- }\r
- return target;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrContext::resetContext() {\r
- fGpu->resetContext();\r
-}\r
-\r
-void GrContext::setRenderTarget(GrRenderTarget* target) {\r
- flush(false);\r
- fGpu->setRenderTarget(target);\r
-}\r
-\r
-GrRenderTarget* GrContext::getRenderTarget() {\r
- return fGpu->getRenderTarget();\r
-}\r
-\r
-const GrRenderTarget* GrContext::getRenderTarget() const {\r
- return fGpu->getRenderTarget();\r
-}\r
-\r
-const GrMatrix& GrContext::getMatrix() const {\r
- return fGpu->getViewMatrix();\r
-}\r
-\r
-void GrContext::setMatrix(const GrMatrix& m) {\r
- fGpu->setViewMatrix(m);\r
-}\r
-\r
-void GrContext::concatMatrix(const GrMatrix& m) const {\r
- fGpu->preConcatViewMatrix(m);\r
-}\r
-\r
-static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {\r
- intptr_t mask = 1 << shift;\r
- if (pred) {\r
- bits |= mask;\r
- } else {\r
- bits &= ~mask;\r
- }\r
- return bits;\r
-}\r
-\r
-void GrContext::resetStats() {\r
- fGpu->resetStats();\r
-}\r
-\r
-const GrGpu::Stats& GrContext::getStats() const {\r
- return fGpu->getStats();\r
-}\r
-\r
-void GrContext::printStats() const {\r
- fGpu->printStats();\r
-}\r
-\r
-GrContext::GrContext(GrGpu* gpu) {\r
- fGpu = gpu;\r
- fGpu->ref();\r
- fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,\r
- MAX_TEXTURE_CACHE_BYTES);\r
- fFontCache = new GrFontCache(fGpu);\r
-\r
- fLastDrawCategory = kUnbuffered_DrawCategory;\r
-\r
-#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT\r
- fDrawBufferVBAllocPool = \r
- new GrVertexBufferAllocPool(gpu, false,\r
- DRAW_BUFFER_VBPOOL_BUFFER_SIZE,\r
- DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);\r
- fDrawBufferIBAllocPool = \r
- new GrIndexBufferAllocPool(gpu, false,\r
- DRAW_BUFFER_IBPOOL_BUFFER_SIZE, \r
- DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);\r
-\r
- fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,\r
- fDrawBufferIBAllocPool);\r
-#else\r
- fDrawBuffer = NULL;\r
- fDrawBufferVBAllocPool = NULL;\r
- fDrawBufferIBAllocPool = NULL;\r
-#endif\r
-\r
-#if BATCH_RECT_TO_RECT\r
- fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());\r
-#endif\r
- fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding());\r
-}\r
-\r
-bool GrContext::finalizeTextureKey(GrTextureKey* key,\r
- const GrSamplerState& sampler) const {\r
- uint32_t bits = 0;\r
- uint16_t width = key->width();\r
- uint16_t height = key->height();\r
-\r
-\r
- if (!fGpu->npotTextureTileSupport()) {\r
- bool isPow2 = GrIsPow2(width) && GrIsPow2(height);\r
-\r
- bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||\r
- (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);\r
-\r
- if (tiled && !isPow2) {\r
- bits |= 1;\r
- bits |= sampler.isFilter() ? 2 : 0;\r
- }\r
- }\r
- key->finalize(bits);\r
- return 0 != bits;\r
-}\r
-\r
-GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {\r
- GrDrawTarget* target;\r
-#if DEFER_TEXT_RENDERING\r
- target = prepareToDraw(paint, kText_DrawCategory);\r
-#else\r
- target = prepareToDraw(paint, kUnbuffered_DrawCategory);\r
-#endif\r
- SetPaint(paint, target);\r
- return target;\r
-}\r
-\r
-const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {\r
- return fGpu->getQuadIndexBuffer();\r
-}\r
+/*
+ Copyright 2010 Google Inc.
+
+ 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.
+ */
+
+#include "GrContext.h"
+#include "GrTypes.h"
+#include "GrTextureCache.h"
+#include "GrTextStrike.h"
+#include "GrMemory.h"
+#include "GrPathIter.h"
+#include "GrClipIterator.h"
+#include "GrIndexBuffer.h"
+#include "GrInOrderDrawBuffer.h"
+#include "GrBufferAllocPool.h"
+#include "GrPathRenderer.h"
+
+#define DEFER_TEXT_RENDERING 1
+
+#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
+
+static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
+static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
+
+static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
+static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
+
+// We are currently only batching Text and drawRectToRect, both
+// of which use the quad index buffer.
+static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
+static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
+
+GrContext* GrContext::Create(GrGpu::Engine engine,
+ GrGpu::Platform3DContext context3D) {
+ GrContext* ctx = NULL;
+ GrGpu* fGpu = GrGpu::Create(engine, context3D);
+ if (NULL != fGpu) {
+ ctx = new GrContext(fGpu);
+ fGpu->unref();
+ }
+ return ctx;
+}
+
+GrContext* GrContext::CreateGLShaderContext() {
+ return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
+}
+
+GrContext::~GrContext() {
+ fGpu->unref();
+ delete fTextureCache;
+ delete fFontCache;
+ delete fDrawBuffer;
+ delete fDrawBufferVBAllocPool;
+ delete fDrawBufferVBAllocPool;
+ delete fPathRenderer;
+}
+
+void GrContext::abandonAllTextures() {
+ fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
+ fFontCache->abandonAll();
+}
+
+GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
+ const GrSamplerState& sampler) {
+ finalizeTextureKey(key, sampler);
+ return fTextureCache->findAndLock(*key);
+}
+
+static void stretchImage(void* dst,
+ int dstW,
+ int dstH,
+ void* src,
+ int srcW,
+ int srcH,
+ int bpp) {
+ GrFixed dx = (srcW << 16) / dstW;
+ GrFixed dy = (srcH << 16) / dstH;
+
+ GrFixed y = dy >> 1;
+
+ int dstXLimit = dstW*bpp;
+ for (int j = 0; j < dstH; ++j) {
+ GrFixed x = dx >> 1;
+ void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
+ void* dstRow = (uint8_t*)dst + j*dstW*bpp;
+ for (int i = 0; i < dstXLimit; i += bpp) {
+ memcpy((uint8_t*) dstRow + i,
+ (uint8_t*) srcRow + (x>>16)*bpp,
+ bpp);
+ x += dx;
+ }
+ y += dy;
+ }
+}
+
+GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
+ const GrSamplerState& sampler,
+ const GrGpu::TextureDesc& desc,
+ void* srcData, size_t rowBytes) {
+ GrAssert(key->width() == desc.fWidth);
+ GrAssert(key->height() == desc.fHeight);
+
+#if GR_DUMP_TEXTURE_UPLOAD
+ GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
+#endif
+
+ GrTextureEntry* entry = NULL;
+ bool special = finalizeTextureKey(key, sampler);
+ if (special) {
+ GrTextureEntry* clampEntry;
+ GrTextureKey clampKey(*key);
+ clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
+
+ if (NULL == clampEntry) {
+ clampEntry = createAndLockTexture(&clampKey,
+ GrSamplerState::ClampNoFilter(),
+ desc, srcData, rowBytes);
+ GrAssert(NULL != clampEntry);
+ if (NULL == clampEntry) {
+ return NULL;
+ }
+ }
+ GrGpu::TextureDesc rtDesc = desc;
+ rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
+ GrGpu::kNoPathRendering_TextureFlag;
+ rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
+ fGpu->minRenderTargetWidth()));
+ rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
+ fGpu->minRenderTargetHeight()));
+
+ GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
+
+ if (NULL != texture) {
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ fGpu->setRenderTarget(texture->asRenderTarget());
+ fGpu->setTexture(0, clampEntry->texture());
+ fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
+ fGpu->setViewMatrix(GrMatrix::I());
+ fGpu->setAlpha(0xff);
+ fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
+ fGpu->disableState(GrDrawTarget::kDither_StateBit |
+ GrDrawTarget::kClip_StateBit |
+ GrDrawTarget::kAntialias_StateBit);
+ GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
+ GrSamplerState::kClamp_WrapMode,
+ sampler.isFilter());
+ fGpu->setSamplerState(0, stretchSampler);
+
+ static const GrVertexLayout layout =
+ GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
+ GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
+
+ if (arg.succeeded()) {
+ GrPoint* verts = (GrPoint*) arg.vertices();
+ verts[0].setIRectFan(0, 0,
+ texture->width(),
+ texture->height(),
+ 2*sizeof(GrPoint));
+ verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
+ fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
+ 0, 4);
+ entry = fTextureCache->createAndLock(*key, texture);
+ }
+ texture->removeRenderTarget();
+ } else {
+ // TODO: Our CPU stretch doesn't filter. But we create separate
+ // stretched textures when the sampler state is either filtered or
+ // not. Either implement filtered stretch blit on CPU or just create
+ // one when FBO case fails.
+
+ rtDesc.fFlags = 0;
+ // no longer need to clamp at min RT size.
+ rtDesc.fWidth = GrNextPow2(desc.fWidth);
+ rtDesc.fHeight = GrNextPow2(desc.fHeight);
+ int bpp = GrTexture::BytesPerPixel(desc.fFormat);
+ GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
+ rtDesc.fWidth *
+ rtDesc.fHeight);
+ stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
+ srcData, desc.fWidth, desc.fHeight, bpp);
+
+ size_t stretchedRowBytes = rtDesc.fWidth * bpp;
+
+ GrTexture* texture = fGpu->createTexture(rtDesc,
+ stretchedPixels.get(),
+ stretchedRowBytes);
+ GrAssert(NULL != texture);
+ entry = fTextureCache->createAndLock(*key, texture);
+ }
+ fTextureCache->unlock(clampEntry);
+
+ } else {
+ GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
+ if (NULL != texture) {
+ entry = fTextureCache->createAndLock(*key, texture);
+ } else {
+ entry = NULL;
+ }
+ }
+ return entry;
+}
+
+void GrContext::unlockTexture(GrTextureEntry* entry) {
+ fTextureCache->unlock(entry);
+}
+
+void GrContext::detachCachedTexture(GrTextureEntry* entry) {
+ fTextureCache->detach(entry);
+}
+
+void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
+ fTextureCache->reattachAndUnlock(entry);
+}
+
+GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
+ void* srcData,
+ size_t rowBytes) {
+ return fGpu->createTexture(desc, srcData, rowBytes);
+}
+
+void GrContext::getTextureCacheLimits(int* maxTextures,
+ size_t* maxTextureBytes) const {
+ fTextureCache->getLimits(maxTextures, maxTextureBytes);
+}
+
+void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
+ fTextureCache->setLimits(maxTextures, maxTextureBytes);
+}
+
+int GrContext::getMaxTextureDimension() {
+ return fGpu->maxTextureDimension();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrRenderTarget* GrContext::createPlatformRenderTarget(
+ intptr_t platformRenderTarget,
+ int stencilBits,
+ int width, int height) {
+ return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
+ width, height);
+}
+
+bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
+ int width, int height) {
+ if (!fGpu->supports8BitPalette()) {
+ return false;
+ }
+
+
+ bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
+
+ if (!isPow2) {
+ if (!fGpu->npotTextureSupport()) {
+ return false;
+ }
+
+ bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
+ sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
+ if (tiled && !fGpu->npotTextureTileSupport()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::setClip(const GrClip& clip) {
+ fGpu->setClip(clip);
+ fGpu->enableState(GrDrawTarget::kClip_StateBit);
+}
+
+void GrContext::setClip(const GrIRect& rect) {
+ GrClip clip;
+ clip.setRect(rect);
+ fGpu->setClip(clip);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::eraseColor(GrColor color) {
+ fGpu->eraseColor(color);
+}
+
+void GrContext::drawPaint(const GrPaint& paint) {
+ // set rect to be big enough to fill the space, but not super-huge, so we
+ // don't overflow fixed-point implementations
+ GrRect r(fGpu->getClip().getBounds());
+ GrMatrix inverse;
+ if (fGpu->getViewInverse(&inverse)) {
+ inverse.mapRect(&r);
+ } else {
+ GrPrintf("---- fGpu->getViewInverse failed\n");
+ }
+ this->drawRect(paint, r);
+}
+
+/* create a triangle strip that strokes the specified triangle. There are 8
+ unique vertices, but we repreat the last 2 to close up. Alternatively we
+ could use an indices array, and then only send 8 verts, but not sure that
+ would be faster.
+ */
+static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
+ GrScalar width) {
+ const GrScalar rad = GrScalarHalf(width);
+
+ verts[0].set(rect.fLeft + rad, rect.fTop + rad);
+ verts[1].set(rect.fLeft - rad, rect.fTop - rad);
+ verts[2].set(rect.fRight - rad, rect.fTop + rad);
+ verts[3].set(rect.fRight + rad, rect.fTop - rad);
+ verts[4].set(rect.fRight - rad, rect.fBottom - rad);
+ verts[5].set(rect.fRight + rad, rect.fBottom + rad);
+ verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
+ verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
+ verts[8] = verts[0];
+ verts[9] = verts[1];
+}
+
+void GrContext::drawRect(const GrPaint& paint,
+ const GrRect& rect,
+ GrScalar width,
+ const GrMatrix* matrix) {
+
+ bool textured = NULL != paint.getTexture();
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ if (width >= 0) {
+ // TODO: consider making static vertex buffers for these cases.
+ // Hairline could be done by just adding closing vertex to
+ // unitSquareVertexBuffer()
+ GrVertexLayout layout = (textured) ?
+ GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
+ 0;
+ static const int worstCaseVertCount = 10;
+ GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
+
+ if (!geo.succeeded()) {
+ return;
+ }
+
+ GrPrimitiveType primType;
+ int vertCount;
+ GrPoint* vertex = geo.positions();
+
+ if (width > 0) {
+ vertCount = 10;
+ primType = kTriangleStrip_PrimitiveType;
+ setStrokeRectStrip(vertex, rect, width);
+ } else {
+ // hairline
+ vertCount = 5;
+ primType = kLineStrip_PrimitiveType;
+ vertex[0].set(rect.fLeft, rect.fTop);
+ vertex[1].set(rect.fRight, rect.fTop);
+ vertex[2].set(rect.fRight, rect.fBottom);
+ vertex[3].set(rect.fLeft, rect.fBottom);
+ vertex[4].set(rect.fLeft, rect.fTop);
+ }
+
+ GrDrawTarget::AutoViewMatrixRestore avmr;
+ if (NULL != matrix) {
+ avmr.set(target);
+ target->preConcatViewMatrix(*matrix);
+ target->preConcatSamplerMatrix(0, *matrix);
+ }
+
+ target->drawNonIndexed(primType, 0, vertCount);
+ } else {
+ #if GR_STATIC_RECT_VB
+ GrVertexLayout layout = (textured) ?
+ GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
+ 0;
+ target->setVertexSourceToBuffer(layout,
+ fGpu->getUnitSquareVertexBuffer());
+ GrDrawTarget::AutoViewMatrixRestore avmr(target);
+ GrMatrix m;
+ m.setAll(rect.width(), 0, rect.fLeft,
+ 0, rect.height(), rect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+
+ if (NULL != matrix) {
+ m.postConcat(*matrix);
+ }
+
+ target->preConcatViewMatrix(m);
+
+ if (textured) {
+ target->preConcatSamplerMatrix(0, m);
+ }
+ target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
+ #else
+ target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
+ #endif
+ }
+}
+
+void GrContext::drawRectToRect(const GrPaint& paint,
+ const GrRect& dstRect,
+ const GrRect& srcRect,
+ const GrMatrix* dstMatrix,
+ const GrMatrix* srcMatrix) {
+
+ if (NULL == paint.getTexture()) {
+ drawRect(paint, dstRect, -1, dstMatrix);
+ return;
+ }
+
+ GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
+
+#if GR_STATIC_RECT_VB
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
+ GrDrawTarget::AutoViewMatrixRestore avmr(target);
+
+ GrMatrix m;
+
+ m.setAll(dstRect.width(), 0, dstRect.fLeft,
+ 0, dstRect.height(), dstRect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+ if (NULL != dstMatrix) {
+ m.postConcat(*dstMatrix);
+ }
+ target->preConcatViewMatrix(m);
+
+ m.setAll(srcRect.width(), 0, srcRect.fLeft,
+ 0, srcRect.height(), srcRect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+ if (NULL != srcMatrix) {
+ m.postConcat(*srcMatrix);
+ }
+ target->preConcatSamplerMatrix(0, m);
+
+ target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
+ target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
+#else
+
+ GrDrawTarget* target;
+#if BATCH_RECT_TO_RECT
+ target = this->prepareToDraw(paint, kBuffered_DrawCategory);
+#else
+ target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+#endif
+
+ const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
+ const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
+ srcRects[0] = &srcRect;
+ srcMatrices[0] = srcMatrix;
+
+ target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
+#endif
+}
+
+void GrContext::drawVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ int vertexCount,
+ const GrPoint positions[],
+ const GrPoint texCoords[],
+ const GrColor colors[],
+ const uint16_t indices[],
+ int indexCount) {
+ GrVertexLayout layout = 0;
+ int vertexSize = sizeof(GrPoint);
+
+ GrDrawTarget::AutoReleaseGeometry geo;
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ if (NULL != paint.getTexture()) {
+ if (NULL == texCoords) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
+ } else {
+ layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
+ vertexSize += sizeof(GrPoint);
+ }
+ }
+
+ if (NULL != colors) {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ vertexSize += sizeof(GrColor);
+ }
+
+ if (sizeof(GrPoint) != vertexSize) {
+ if (!geo.set(target, layout, vertexCount, 0)) {
+ GrPrintf("Failed to get space for vertices!");
+ return;
+ }
+ int texOffsets[GrDrawTarget::kMaxTexCoords];
+ int colorOffset;
+ int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
+ texOffsets,
+ &colorOffset);
+ void* curVertex = geo.vertices();
+
+ for (int i = 0; i < vertexCount; ++i) {
+ *((GrPoint*)curVertex) = positions[i];
+
+ if (texOffsets[0] > 0) {
+ *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
+ }
+ if (colorOffset > 0) {
+ *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
+ }
+ curVertex = (void*)((intptr_t)curVertex + vsize);
+ }
+ } else {
+ target->setVertexSourceToArray(layout, positions, vertexCount);
+ }
+
+ if (NULL != indices) {
+ target->setIndexSourceToArray(indices, indexCount);
+ target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+ } else {
+ target->drawNonIndexed(primitiveType, 0, vertexCount);
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::drawPath(const GrPaint& paint,
+ GrPathIter* path,
+ GrPathFill fill,
+ const GrPoint* translate) {
+
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ GrDrawTarget::StageBitfield enabledStages = 0;
+ if (NULL != paint.getTexture()) {
+ enabledStages |= 1;
+ }
+ fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::flush(bool flushRenderTarget) {
+ flushDrawBuffer();
+ if (flushRenderTarget) {
+ fGpu->forceRenderTargetFlush();
+ }
+}
+
+void GrContext::flushText() {
+ if (kText_DrawCategory == fLastDrawCategory) {
+ flushDrawBuffer();
+ }
+}
+
+void GrContext::flushDrawBuffer() {
+#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
+ fDrawBuffer->playback(fGpu);
+ fDrawBuffer->reset();
+#endif
+}
+
+bool GrContext::readPixels(int left, int top, int width, int height,
+ GrTexture::PixelConfig config, void* buffer) {
+ this->flush(true);
+ return fGpu->readPixels(left, top, width, height, config, buffer);
+}
+
+void GrContext::writePixels(int left, int top, int width, int height,
+ GrTexture::PixelConfig config, const void* buffer,
+ size_t stride) {
+
+ // TODO: when underlying api has a direct way to do this we should use it
+ // (e.g. glDrawPixels on desktop GL).
+
+ const GrGpu::TextureDesc desc = {
+ 0, GrGpu::kNone_AALevel, width, height, config
+ };
+ GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
+ if (NULL == texture) {
+ return;
+ }
+
+ this->flush(true);
+
+ GrAutoUnref aur(texture);
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+
+ GrMatrix matrix;
+ matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
+ fGpu->setViewMatrix(matrix);
+
+ fGpu->disableState(GrDrawTarget::kClip_StateBit);
+ fGpu->setAlpha(0xFF);
+ fGpu->setBlendFunc(kOne_BlendCoeff,
+ kZero_BlendCoeff);
+ fGpu->setTexture(0, texture);
+
+ GrSamplerState sampler;
+ sampler.setClampNoFilter();
+ matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
+ sampler.setMatrix(matrix);
+ fGpu->setSamplerState(0, sampler);
+
+ GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
+ static const int VCOUNT = 4;
+
+ GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
+ if (!geo.succeeded()) {
+ return;
+ }
+ ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
+ fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
+}
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
+ target->setTexture(0, paint.getTexture());
+ target->setSamplerState(0, paint.fSampler);
+ target->setColor(paint.fColor);
+
+ if (paint.fDither) {
+ target->enableState(GrDrawTarget::kDither_StateBit);
+ } else {
+ target->disableState(GrDrawTarget::kDither_StateBit);
+ }
+ if (paint.fAntiAlias) {
+ target->enableState(GrDrawTarget::kAntialias_StateBit);
+ } else {
+ target->disableState(GrDrawTarget::kAntialias_StateBit);
+ }
+ target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
+}
+
+GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
+ DrawCategory category) {
+ if (category != fLastDrawCategory) {
+ flushDrawBuffer();
+ fLastDrawCategory = category;
+ }
+ SetPaint(paint, fGpu);
+ GrDrawTarget* target = fGpu;
+ switch (category) {
+ case kText_DrawCategory:
+#if DEFER_TEXT_RENDERING
+ target = fDrawBuffer;
+ fDrawBuffer->initializeDrawStateAndClip(*fGpu);
+#else
+ target = fGpu;
+#endif
+ break;
+ case kUnbuffered_DrawCategory:
+ target = fGpu;
+ break;
+ case kBuffered_DrawCategory:
+ target = fDrawBuffer;
+ fDrawBuffer->initializeDrawStateAndClip(*fGpu);
+ break;
+ }
+ return target;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::resetContext() {
+ fGpu->resetContext();
+}
+
+void GrContext::setRenderTarget(GrRenderTarget* target) {
+ flush(false);
+ fGpu->setRenderTarget(target);
+}
+
+GrRenderTarget* GrContext::getRenderTarget() {
+ return fGpu->getRenderTarget();
+}
+
+const GrRenderTarget* GrContext::getRenderTarget() const {
+ return fGpu->getRenderTarget();
+}
+
+const GrMatrix& GrContext::getMatrix() const {
+ return fGpu->getViewMatrix();
+}
+
+void GrContext::setMatrix(const GrMatrix& m) {
+ fGpu->setViewMatrix(m);
+}
+
+void GrContext::concatMatrix(const GrMatrix& m) const {
+ fGpu->preConcatViewMatrix(m);
+}
+
+static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
+ intptr_t mask = 1 << shift;
+ if (pred) {
+ bits |= mask;
+ } else {
+ bits &= ~mask;
+ }
+ return bits;
+}
+
+void GrContext::resetStats() {
+ fGpu->resetStats();
+}
+
+const GrGpu::Stats& GrContext::getStats() const {
+ return fGpu->getStats();
+}
+
+void GrContext::printStats() const {
+ fGpu->printStats();
+}
+
+GrContext::GrContext(GrGpu* gpu) {
+ fGpu = gpu;
+ fGpu->ref();
+ fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
+ MAX_TEXTURE_CACHE_BYTES);
+ fFontCache = new GrFontCache(fGpu);
+
+ fLastDrawCategory = kUnbuffered_DrawCategory;
+
+#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
+ fDrawBufferVBAllocPool =
+ new GrVertexBufferAllocPool(gpu, false,
+ DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
+ DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
+ fDrawBufferIBAllocPool =
+ new GrIndexBufferAllocPool(gpu, false,
+ DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
+ DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
+
+ fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
+ fDrawBufferIBAllocPool);
+#else
+ fDrawBuffer = NULL;
+ fDrawBufferVBAllocPool = NULL;
+ fDrawBufferIBAllocPool = NULL;
+#endif
+
+#if BATCH_RECT_TO_RECT
+ fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
+#endif
+ fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding());
+}
+
+bool GrContext::finalizeTextureKey(GrTextureKey* key,
+ const GrSamplerState& sampler) const {
+ uint32_t bits = 0;
+ uint16_t width = key->width();
+ uint16_t height = key->height();
+
+
+ if (!fGpu->npotTextureTileSupport()) {
+ bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
+
+ bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
+ (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
+
+ if (tiled && !isPow2) {
+ bits |= 1;
+ bits |= sampler.isFilter() ? 2 : 0;
+ }
+ }
+ key->finalize(bits);
+ return 0 != bits;
+}
+
+GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
+ GrDrawTarget* target;
+#if DEFER_TEXT_RENDERING
+ target = prepareToDraw(paint, kText_DrawCategory);
+#else
+ target = prepareToDraw(paint, kUnbuffered_DrawCategory);
+#endif
+ SetPaint(paint, target);
+ return target;
+}
+
+const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
+ return fGpu->getQuadIndexBuffer();
+}
-/*\r
- Copyright 2010 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-#include "GrGLConfig.h"\r
-#include "GrTypes.h"\r
-#include <stdio.h>\r
-\r
-bool has_gl_extension(const char* ext) {\r
- const char* glstr = (const char*) glGetString(GL_EXTENSIONS);\r
-\r
- int extLength = strlen(ext);\r
-\r
- while (true) {\r
- int n = strcspn(glstr, " ");\r
- if (n == extLength && 0 == strncmp(ext, glstr, n)) {\r
- return true;\r
- }\r
- if (0 == glstr[n]) {\r
- return false;\r
- }\r
- glstr += n+1;\r
- }\r
-}\r
-\r
-void gl_version(int* major, int* minor) {\r
- const char* v = (const char*) glGetString(GL_VERSION);\r
- if (NULL == v) {\r
- GrAssert(0);\r
- *major = 0;\r
- *minor = 0;\r
- return;\r
- }\r
-#if GR_SUPPORT_GLDESKTOP\r
- int n = sscanf(v, "%d.%d", major, minor);\r
- if (n != 2) {\r
- GrAssert(0);\r
- *major = 0;\r
- *minor = 0;\r
- return;\r
- }\r
-#else\r
- char profile[2];\r
- int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor);\r
- bool ok = 4 == n;\r
- if (!ok) {\r
- int n = sscanf(v, "OpenGL ES %d.%d", major, minor);\r
- ok = 2 == n;\r
- }\r
- if (!ok) {\r
- GrAssert(0);\r
- *major = 0;\r
- *minor = 0;\r
- return;\r
- }\r
-#endif\r
-}\r
-\r
-#if defined(GR_GL_PROC_ADDRESS_HEADER)\r
- #include GR_GL_PROC_ADDRESS_HEADER\r
-#endif\r
-\r
-typedef void (*glProc)(void);\r
-\r
-#define GET_PROC(EXT_STRUCT, PROC_NAME) \\r
- *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME)); \\r
- GrAssert(NULL != EXT_STRUCT-> PROC_NAME)\r
-\r
-#define GET_SUFFIX_PROC(EXT_STRUCT, PROC_NAME, SUFFIX) \\r
- *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME ## SUFFIX)); \\r
- GrAssert(NULL != EXT_STRUCT-> PROC_NAME)\r
-\r
-extern void GrGLInitExtensions(GrGLExts* exts) {\r
- exts->GenFramebuffers = NULL;\r
- exts->BindFramebuffer = NULL;\r
- exts->FramebufferTexture2D = NULL;\r
- exts->CheckFramebufferStatus = NULL;\r
- exts->DeleteFramebuffers = NULL;\r
- exts->RenderbufferStorage = NULL;\r
- exts->GenRenderbuffers = NULL;\r
- exts->DeleteRenderbuffers = NULL;\r
- exts->FramebufferRenderbuffer = NULL;\r
- exts->BindRenderbuffer = NULL;\r
- exts->RenderbufferStorageMultisample = NULL;\r
- exts->BlitFramebuffer = NULL;\r
- exts->ResolveMultisampleFramebuffer = NULL;\r
- exts->FramebufferTexture2DMultisample = NULL;\r
- exts->MapBuffer = NULL;\r
- exts->UnmapBuffer = NULL;\r
-\r
- GLint major, minor;\r
- gl_version(&major, &minor);\r
-\r
- bool fboFound = false;\r
-#if GR_SUPPORT_GLDESKTOP\r
- #if defined(GL_VERSION_3_0) && GL_VERSION_3_0\r
- if (!fboFound && major >= 3) { // all of ARB_fbo is in 3.x\r
- exts->GenFramebuffers = glGenFramebuffers;\r
- exts->BindFramebuffer = glBindFramebuffer;\r
- exts->FramebufferTexture2D = glFramebufferTexture2D;\r
- exts->CheckFramebufferStatus = glCheckFramebufferStatus;\r
- exts->DeleteFramebuffers = glDeleteFramebuffers;\r
- exts->RenderbufferStorage = glRenderbufferStorage;\r
- exts->GenRenderbuffers = glGenRenderbuffers;\r
- exts->DeleteRenderbuffers = glDeleteRenderbuffers;\r
- exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;\r
- exts->BindRenderbuffer = glBindRenderbuffer;\r
- exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;\r
- exts->BlitFramebuffer = glBlitFramebuffer;\r
- fboFound = true;\r
- }\r
- #endif\r
- #if GL_ARB_framebuffer_object\r
- if (!fboFound && has_gl_extension("GL_ARB_framebuffer_object")) {\r
- // GL_ARB_framebuffer_object doesn't use ARB suffix.\r
- GET_PROC(exts, GenFramebuffers);\r
- GET_PROC(exts, BindFramebuffer);\r
- GET_PROC(exts, FramebufferTexture2D);\r
- GET_PROC(exts, CheckFramebufferStatus);\r
- GET_PROC(exts, DeleteFramebuffers);\r
- GET_PROC(exts, RenderbufferStorage);\r
- GET_PROC(exts, GenRenderbuffers);\r
- GET_PROC(exts, DeleteRenderbuffers);\r
- GET_PROC(exts, FramebufferRenderbuffer);\r
- GET_PROC(exts, BindRenderbuffer);\r
- GET_PROC(exts, RenderbufferStorageMultisample);\r
- GET_PROC(exts, BlitFramebuffer);\r
- fboFound = true;\r
- }\r
- #endif\r
- // Mac doesn't declare prototypes for EXT FBO extensions\r
- #if GL_EXT_framebuffer_object && !GR_MAC_BUILD\r
- if (!fboFound && has_gl_extension("GL_EXT_framebuffer_object")) {\r
- GET_SUFFIX_PROC(exts, GenFramebuffers, EXT);\r
- GET_SUFFIX_PROC(exts, BindFramebuffer, EXT);\r
- GET_SUFFIX_PROC(exts, FramebufferTexture2D, EXT);\r
- GET_SUFFIX_PROC(exts, CheckFramebufferStatus, EXT);\r
- GET_SUFFIX_PROC(exts, DeleteFramebuffers, EXT);\r
- GET_SUFFIX_PROC(exts, RenderbufferStorage, EXT);\r
- GET_SUFFIX_PROC(exts, GenRenderbuffers, EXT);\r
- GET_SUFFIX_PROC(exts, DeleteRenderbuffers, EXT);\r
- GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, EXT);\r
- GET_SUFFIX_PROC(exts, BindRenderbuffer, EXT);\r
- fboFound = true;\r
- // check for fbo ms and fbo blit\r
- #if GL_EXT_framebuffer_multisample\r
- if (has_gl_extension("GL_EXT_framebuffer_multisample")) {\r
- GET_SUFFIX_PROC(exts, RenderbufferStorageMultisample, EXT);\r
- }\r
- #endif\r
- #if GL_EXT_framebuffer_blit\r
- if (has_gl_extension("GL_EXT_framebuffer_blit")) {\r
- GET_SUFFIX_PROC(exts, BlitFramebuffer, EXT);\r
- }\r
- #endif\r
- }\r
- #endif\r
- if (!fboFound) {\r
- // we require some form of FBO\r
- GrAssert(!"No FBOs supported?");\r
- }\r
- // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)\r
- exts->MapBuffer = glMapBuffer;\r
- exts->UnmapBuffer = glUnmapBuffer;\r
-#else // !GR_SUPPORT_GLDESKTOP\r
- #if GR_SUPPORT_GLES2\r
- if (!fboFound && major >= 2) {// ES 2.0 supports FBO\r
- exts->GenFramebuffers = glGenFramebuffers;\r
- exts->BindFramebuffer = glBindFramebuffer;\r
- exts->FramebufferTexture2D = glFramebufferTexture2D;\r
- exts->CheckFramebufferStatus = glCheckFramebufferStatus;\r
- exts->DeleteFramebuffers = glDeleteFramebuffers;\r
- exts->RenderbufferStorage = glRenderbufferStorage;\r
- exts->GenRenderbuffers = glGenRenderbuffers;\r
- exts->DeleteRenderbuffers = glDeleteRenderbuffers;\r
- exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;\r
- exts->BindRenderbuffer = glBindRenderbuffer;\r
- fboFound = true;\r
- }\r
- #endif\r
- #if GL_OES_framebuffer_object\r
- if (!fboFound && has_gl_extension("GL_OES_framebuffer_object")) {\r
- GET_SUFFIX_PROC(exts, GenFramebuffers, OES);\r
- GET_SUFFIX_PROC(exts, BindFramebuffer, OES);\r
- GET_SUFFIX_PROC(exts, FramebufferTexture2D, OES);\r
- GET_SUFFIX_PROC(exts, CheckFramebufferStatus, OES);\r
- GET_SUFFIX_PROC(exts, DeleteFramebuffers, OES);\r
- GET_SUFFIX_PROC(exts, RenderbufferStorage, OES);\r
- GET_SUFFIX_PROC(exts, GenRenderbuffers, OES);\r
- GET_SUFFIX_PROC(exts, DeleteRenderbuffers, OES);\r
- GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, OES);\r
- GET_SUFFIX_PROC(exts, BindRenderbuffer, OES);\r
- }\r
- #endif\r
-\r
- if (!fboFound) {\r
- // we require some form of FBO\r
- GrAssert(!"No FBOs supported?");\r
- }\r
-\r
- #if GL_APPLE_framebuffer_multisample\r
- if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {\r
- GET_SUFFIX_PROC(exts, ResolveMultisampleFramebuffer, APPLE);\r
- }\r
- #endif\r
-\r
- #if GL_IMG_multisampled_render_to_texture\r
- if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {\r
- GET_SUFFIX_PROC(exts, FramebufferTexture2DMultisample, IMG);\r
- }\r
- #endif\r
-\r
- #if GL_OES_mapbuffer\r
- if (has_gl_extension("GL_OES_mapbuffer")) {\r
- GET_SUFFIX_PROC(exts, MapBuffer, OES);\r
- GET_SUFFIX_PROC(exts, UnmapBuffer, OES);\r
- }\r
- #endif\r
-#endif // !GR_SUPPORT_GLDESKTOP\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-\r
-void GrGLCheckErr(const char* location, const char* call) {\r
- uint32_t err = glGetError();\r
- if (GL_NO_ERROR != err) {\r
- GrPrintf("---- glGetError %x", err);\r
- if (NULL != location) {\r
- GrPrintf(" at\n\t%s", location);\r
- }\r
- if (NULL != call) {\r
- GrPrintf("\n\t\t%s", call);\r
- }\r
- GrPrintf("\n");\r
- }\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-\r
-bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START);\r
-\r
-bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START);\r
+/*
+ Copyright 2010 Google Inc.
+
+ 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.
+ */
+
+#include "GrGLConfig.h"
+#include "GrTypes.h"
+#include <stdio.h>
+
+bool has_gl_extension(const char* ext) {
+ const char* glstr = (const char*) glGetString(GL_EXTENSIONS);
+
+ int extLength = strlen(ext);
+
+ while (true) {
+ int n = strcspn(glstr, " ");
+ if (n == extLength && 0 == strncmp(ext, glstr, n)) {
+ return true;
+ }
+ if (0 == glstr[n]) {
+ return false;
+ }
+ glstr += n+1;
+ }
+}
+
+void gl_version(int* major, int* minor) {
+ const char* v = (const char*) glGetString(GL_VERSION);
+ if (NULL == v) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#if GR_SUPPORT_GLDESKTOP
+ int n = sscanf(v, "%d.%d", major, minor);
+ if (n != 2) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#else
+ char profile[2];
+ int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor);
+ bool ok = 4 == n;
+ if (!ok) {
+ int n = sscanf(v, "OpenGL ES %d.%d", major, minor);
+ ok = 2 == n;
+ }
+ if (!ok) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#endif
+}
+
+#if defined(GR_GL_PROC_ADDRESS_HEADER)
+ #include GR_GL_PROC_ADDRESS_HEADER
+#endif
+
+typedef void (*glProc)(void);
+
+#define GET_PROC(EXT_STRUCT, PROC_NAME) \
+ *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME)); \
+ GrAssert(NULL != EXT_STRUCT-> PROC_NAME)
+
+#define GET_SUFFIX_PROC(EXT_STRUCT, PROC_NAME, SUFFIX) \
+ *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME ## SUFFIX)); \
+ GrAssert(NULL != EXT_STRUCT-> PROC_NAME)
+
+extern void GrGLInitExtensions(GrGLExts* exts) {
+ exts->GenFramebuffers = NULL;
+ exts->BindFramebuffer = NULL;
+ exts->FramebufferTexture2D = NULL;
+ exts->CheckFramebufferStatus = NULL;
+ exts->DeleteFramebuffers = NULL;
+ exts->RenderbufferStorage = NULL;
+ exts->GenRenderbuffers = NULL;
+ exts->DeleteRenderbuffers = NULL;
+ exts->FramebufferRenderbuffer = NULL;
+ exts->BindRenderbuffer = NULL;
+ exts->RenderbufferStorageMultisample = NULL;
+ exts->BlitFramebuffer = NULL;
+ exts->ResolveMultisampleFramebuffer = NULL;
+ exts->FramebufferTexture2DMultisample = NULL;
+ exts->MapBuffer = NULL;
+ exts->UnmapBuffer = NULL;
+
+ GLint major, minor;
+ gl_version(&major, &minor);
+
+ bool fboFound = false;
+#if GR_SUPPORT_GLDESKTOP
+ #if defined(GL_VERSION_3_0) && GL_VERSION_3_0
+ if (!fboFound && major >= 3) { // all of ARB_fbo is in 3.x
+ exts->GenFramebuffers = glGenFramebuffers;
+ exts->BindFramebuffer = glBindFramebuffer;
+ exts->FramebufferTexture2D = glFramebufferTexture2D;
+ exts->CheckFramebufferStatus = glCheckFramebufferStatus;
+ exts->DeleteFramebuffers = glDeleteFramebuffers;
+ exts->RenderbufferStorage = glRenderbufferStorage;
+ exts->GenRenderbuffers = glGenRenderbuffers;
+ exts->DeleteRenderbuffers = glDeleteRenderbuffers;
+ exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
+ exts->BindRenderbuffer = glBindRenderbuffer;
+ exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample;
+ exts->BlitFramebuffer = glBlitFramebuffer;
+ fboFound = true;
+ }
+ #endif
+ #if GL_ARB_framebuffer_object
+ if (!fboFound && has_gl_extension("GL_ARB_framebuffer_object")) {
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.
+ GET_PROC(exts, GenFramebuffers);
+ GET_PROC(exts, BindFramebuffer);
+ GET_PROC(exts, FramebufferTexture2D);
+ GET_PROC(exts, CheckFramebufferStatus);
+ GET_PROC(exts, DeleteFramebuffers);
+ GET_PROC(exts, RenderbufferStorage);
+ GET_PROC(exts, GenRenderbuffers);
+ GET_PROC(exts, DeleteRenderbuffers);
+ GET_PROC(exts, FramebufferRenderbuffer);
+ GET_PROC(exts, BindRenderbuffer);
+ GET_PROC(exts, RenderbufferStorageMultisample);
+ GET_PROC(exts, BlitFramebuffer);
+ fboFound = true;
+ }
+ #endif
+ // Mac doesn't declare prototypes for EXT FBO extensions
+ #if GL_EXT_framebuffer_object && !GR_MAC_BUILD
+ if (!fboFound && has_gl_extension("GL_EXT_framebuffer_object")) {
+ GET_SUFFIX_PROC(exts, GenFramebuffers, EXT);
+ GET_SUFFIX_PROC(exts, BindFramebuffer, EXT);
+ GET_SUFFIX_PROC(exts, FramebufferTexture2D, EXT);
+ GET_SUFFIX_PROC(exts, CheckFramebufferStatus, EXT);
+ GET_SUFFIX_PROC(exts, DeleteFramebuffers, EXT);
+ GET_SUFFIX_PROC(exts, RenderbufferStorage, EXT);
+ GET_SUFFIX_PROC(exts, GenRenderbuffers, EXT);
+ GET_SUFFIX_PROC(exts, DeleteRenderbuffers, EXT);
+ GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, EXT);
+ GET_SUFFIX_PROC(exts, BindRenderbuffer, EXT);
+ fboFound = true;
+ // check for fbo ms and fbo blit
+ #if GL_EXT_framebuffer_multisample
+ if (has_gl_extension("GL_EXT_framebuffer_multisample")) {
+ GET_SUFFIX_PROC(exts, RenderbufferStorageMultisample, EXT);
+ }
+ #endif
+ #if GL_EXT_framebuffer_blit
+ if (has_gl_extension("GL_EXT_framebuffer_blit")) {
+ GET_SUFFIX_PROC(exts, BlitFramebuffer, EXT);
+ }
+ #endif
+ }
+ #endif
+ if (!fboFound) {
+ // we require some form of FBO
+ GrAssert(!"No FBOs supported?");
+ }
+ // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
+ exts->MapBuffer = glMapBuffer;
+ exts->UnmapBuffer = glUnmapBuffer;
+#else // !GR_SUPPORT_GLDESKTOP
+ #if GR_SUPPORT_GLES2
+ if (!fboFound && major >= 2) {// ES 2.0 supports FBO
+ exts->GenFramebuffers = glGenFramebuffers;
+ exts->BindFramebuffer = glBindFramebuffer;
+ exts->FramebufferTexture2D = glFramebufferTexture2D;
+ exts->CheckFramebufferStatus = glCheckFramebufferStatus;
+ exts->DeleteFramebuffers = glDeleteFramebuffers;
+ exts->RenderbufferStorage = glRenderbufferStorage;
+ exts->GenRenderbuffers = glGenRenderbuffers;
+ exts->DeleteRenderbuffers = glDeleteRenderbuffers;
+ exts->FramebufferRenderbuffer = glFramebufferRenderbuffer;
+ exts->BindRenderbuffer = glBindRenderbuffer;
+ fboFound = true;
+ }
+ #endif
+ #if GL_OES_framebuffer_object
+ if (!fboFound && has_gl_extension("GL_OES_framebuffer_object")) {
+ GET_SUFFIX_PROC(exts, GenFramebuffers, OES);
+ GET_SUFFIX_PROC(exts, BindFramebuffer, OES);
+ GET_SUFFIX_PROC(exts, FramebufferTexture2D, OES);
+ GET_SUFFIX_PROC(exts, CheckFramebufferStatus, OES);
+ GET_SUFFIX_PROC(exts, DeleteFramebuffers, OES);
+ GET_SUFFIX_PROC(exts, RenderbufferStorage, OES);
+ GET_SUFFIX_PROC(exts, GenRenderbuffers, OES);
+ GET_SUFFIX_PROC(exts, DeleteRenderbuffers, OES);
+ GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, OES);
+ GET_SUFFIX_PROC(exts, BindRenderbuffer, OES);
+ }
+ #endif
+
+ if (!fboFound) {
+ // we require some form of FBO
+ GrAssert(!"No FBOs supported?");
+ }
+
+ #if GL_APPLE_framebuffer_multisample
+ if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
+ GET_SUFFIX_PROC(exts, ResolveMultisampleFramebuffer, APPLE);
+ }
+ #endif
+
+ #if GL_IMG_multisampled_render_to_texture
+ if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) {
+ GET_SUFFIX_PROC(exts, FramebufferTexture2DMultisample, IMG);
+ }
+ #endif
+
+ #if GL_OES_mapbuffer
+ if (has_gl_extension("GL_OES_mapbuffer")) {
+ GET_SUFFIX_PROC(exts, MapBuffer, OES);
+ GET_SUFFIX_PROC(exts, UnmapBuffer, OES);
+ }
+ #endif
+#endif // !GR_SUPPORT_GLDESKTOP
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGLCheckErr(const char* location, const char* call) {
+ uint32_t err = glGetError();
+ if (GL_NO_ERROR != err) {
+ GrPrintf("---- glGetError %x", err);
+ if (NULL != location) {
+ GrPrintf(" at\n\t%s", location);
+ }
+ if (NULL != call) {
+ GrPrintf("\n\t\t%s", call);
+ }
+ GrPrintf("\n");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START);
+
+bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START);
-/*\r
- Copyright 2010 Google Inc.\r
-\r
- Licensed under the Apache License, Version 2.0 (the "License");\r
- you may not use this file except in compliance with the License.\r
- You may obtain a copy of the License at\r
-\r
- http://www.apache.org/licenses/LICENSE-2.0\r
-\r
- Unless required by applicable law or agreed to in writing, software\r
- distributed under the License is distributed on an "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- See the License for the specific language governing permissions and\r
- limitations under the License.\r
- */\r
-\r
-\r
-#include "GrMatrix.h"\r
-#include "GrRect.h"\r
-#include <stddef.h>\r
-\r
-#if GR_SCALAR_IS_FLOAT\r
- const GrScalar GrMatrix::gRESCALE(GR_Scalar1);\r
-#else\r
- GR_STATIC_ASSERT(GR_SCALAR_IS_FIXED);\r
- // fixed point isn't supported right now\r
- GR_STATIC_ASSERT(false);\r
-const GrScalar GrMatrix::gRESCALE(1 << 30);\r
-#endif\r
-\r
-const GrMatrix::MapProc GrMatrix::gMapProcs[] = {\r
-// Scales are not both zero\r
- &GrMatrix::mapIdentity,\r
- &GrMatrix::mapScale,\r
- &GrMatrix::mapTranslate,\r
- &GrMatrix::mapScaleAndTranslate,\r
- &GrMatrix::mapSkew,\r
- &GrMatrix::mapScaleAndSkew,\r
- &GrMatrix::mapSkewAndTranslate,\r
- &GrMatrix::mapNonPerspective,\r
- // no optimizations for perspective matrices\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapPerspective,\r
-\r
-// Scales are zero (every other is invalid because kScale_TypeBit must be set if\r
-// kZeroScale_TypeBit is set)\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapZero,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapSetToTranslate,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapSwappedScale,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapSwappedScaleAndTranslate,\r
-\r
- // no optimizations for perspective matrices\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapZero,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapPerspective,\r
- &GrMatrix::mapInvalid,\r
- &GrMatrix::mapPerspective,\r
-};\r
-\r
-void GrMatrix::setIdentity() {\r
- fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = 0;\r
- fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = 0;\r
- fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;\r
- fTypeMask = 0;\r
-}\r
-\r
-void GrMatrix::setTranslate(GrScalar dx, GrScalar dy) {\r
- fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = dx;\r
- fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = dy;\r
- fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;\r
- fTypeMask = (0 != dx || 0 != dy) ? kTranslate_TypeBit : 0;\r
-}\r
-\r
-void GrMatrix::setScale(GrScalar sx, GrScalar sy) {\r
- fM[0] = sx; fM[1] = 0; fM[2] = 0;\r
- fM[3] = 0; fM[4] = sy; fM[5] = 0;\r
- fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;\r
- fTypeMask = (GR_Scalar1 != sx || GR_Scalar1 != sy) ? kScale_TypeBit : 0;\r
-}\r
-\r
-void GrMatrix::setSkew(GrScalar skx, GrScalar sky) {\r
- fM[0] = GR_Scalar1; fM[1] = skx; fM[2] = 0;\r
- fM[3] = sky; fM[4] = GR_Scalar1; fM[5] = 0;\r
- fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;\r
- fTypeMask = (0 != skx || 0 != sky) ? kSkew_TypeBit : 0;\r
-}\r
-\r
-void GrMatrix::setConcat(const GrMatrix& a, const GrMatrix& b) {\r
- if (a.isIdentity()) {\r
- if (this != &b) {\r
- for (int i = 0; i < 9; ++i) {\r
- fM[i] = b.fM[i];\r
- }\r
- fTypeMask = b.fTypeMask;\r
- }\r
- return;\r
- }\r
-\r
- if (b.isIdentity()) {\r
- GrAssert(!a.isIdentity());\r
- if (this != &a) {\r
- for (int i = 0; i < 9; ++i) {\r
- fM[i] = a.fM[i];\r
- }\r
- fTypeMask = a.fTypeMask;\r
- }\r
- return;\r
- }\r
-\r
- // a and/or b could be this\r
- GrMatrix tmp;\r
-\r
- // could do more optimizations based on type bits. Hopefully this call is\r
- // low frequency.\r
- // TODO: make this work for fixed point\r
- if (!((b.fTypeMask | a.fTypeMask) & kPerspective_TypeBit)) {\r
- tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3];\r
- tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4];\r
- tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * gRESCALE;\r
-\r
- tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3];\r
- tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4];\r
- tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * gRESCALE;\r
-\r
- tmp.fM[6] = 0;\r
- tmp.fM[7] = 0;\r
- tmp.fM[8] = gRESCALE * gRESCALE;\r
- } else {\r
- tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3] + a.fM[2] * b.fM[6];\r
- tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4] + a.fM[2] * b.fM[7];\r
- tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * b.fM[8];\r
-\r
- tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3] + a.fM[5] * b.fM[6];\r
- tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4] + a.fM[5] * b.fM[7];\r
- tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * b.fM[8];\r
-\r
- tmp.fM[6] = a.fM[6] * b.fM[0] + a.fM[7] * b.fM[3] + a.fM[8] * b.fM[6];\r
- tmp.fM[7] = a.fM[6] * b.fM[1] + a.fM[7] * b.fM[4] + a.fM[8] * b.fM[7];\r
- tmp.fM[8] = a.fM[6] * b.fM[2] + a.fM[7] * b.fM[5] + a.fM[8] * b.fM[8];\r
- }\r
- *this = tmp;\r
- this->computeTypeMask();\r
-}\r
-\r
-void GrMatrix::preConcat(const GrMatrix& m) {\r
- setConcat(*this, m);\r
-}\r
-\r
-void GrMatrix::postConcat(const GrMatrix& m) {\r
- setConcat(m, *this);\r
-}\r
-\r
-double GrMatrix::determinant() const {\r
- if (fTypeMask & kPerspective_TypeBit) {\r
- return fM[0]*((double)fM[4]*fM[8] - (double)fM[5]*fM[7]) +\r
- fM[1]*((double)fM[5]*fM[6] - (double)fM[3]*fM[8]) +\r
- fM[2]*((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);\r
- } else {\r
- return (double)fM[0]*fM[4]*gRESCALE -\r
- (double)fM[1]*fM[3]*gRESCALE;\r
- }\r
-}\r
-\r
-bool GrMatrix::invert(GrMatrix* inverted) const {\r
-\r
- if (isIdentity()) {\r
- if (inverted != this) {\r
- inverted->setIdentity();\r
- }\r
- return true;\r
- }\r
- static const double MIN_DETERMINANT_SQUARED = 1.e-16;\r
-\r
- // could do more optimizations based on type bits. Hopefully this call is\r
- // low frequency.\r
-\r
- double det = determinant();\r
-\r
- // check if we can't be inverted\r
- if (det*det <= MIN_DETERMINANT_SQUARED) {\r
- return false;\r
- } else if (NULL == inverted) {\r
- return true;\r
- }\r
-\r
- double t[9];\r
-\r
- if (fTypeMask & kPerspective_TypeBit) {\r
- t[0] = ((double)fM[4]*fM[8] - (double)fM[5]*fM[7]);\r
- t[1] = ((double)fM[2]*fM[7] - (double)fM[1]*fM[8]);\r
- t[2] = ((double)fM[1]*fM[5] - (double)fM[2]*fM[4]);\r
- t[3] = ((double)fM[5]*fM[6] - (double)fM[3]*fM[8]);\r
- t[4] = ((double)fM[0]*fM[8] - (double)fM[2]*fM[6]);\r
- t[5] = ((double)fM[2]*fM[3] - (double)fM[0]*fM[5]);\r
- t[6] = ((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);\r
- t[7] = ((double)fM[1]*fM[6] - (double)fM[0]*fM[7]);\r
- t[8] = ((double)fM[0]*fM[4] - (double)fM[1]*fM[3]);\r
- det = 1.0 / det;\r
- for (int i = 0; i < 9; ++i) {\r
- inverted->fM[i] = (GrScalar)(t[i] * det);\r
- }\r
- } else {\r
- t[0] = (double)fM[4]*gRESCALE;\r
- t[1] = -(double)fM[1]*gRESCALE;\r
- t[2] = (double)fM[1]*fM[5] - (double)fM[2]*fM[4];\r
- t[3] = -(double)fM[3]*gRESCALE;\r
- t[4] = (double)fM[0]*gRESCALE;\r
- t[5] = (double)fM[2]*fM[3] - (double)fM[0]*fM[5];\r
- //t[6] = 0.0;\r
- //t[7] = 0.0;\r
- t[8] = (double)fM[0]*fM[4] - (double)fM[1]*fM[3];\r
- det = 1.0 / det;\r
- for (int i = 0; i < 6; ++i) {\r
- inverted->fM[i] = (GrScalar)(t[i] * det);\r
- }\r
- inverted->fM[6] = 0;\r
- inverted->fM[7] = 0;\r
- inverted->fM[8] = (GrScalar)(t[8] * det);\r
- }\r
- inverted->computeTypeMask();\r
- return true;\r
-}\r
-\r
-void GrMatrix::mapRect(GrRect* dst, const GrRect& src) const {\r
- GrPoint srcPts[4], dstPts[4];\r
- srcPts[0].set(src.fLeft, src.fTop);\r
- srcPts[1].set(src.fRight, src.fTop);\r
- srcPts[2].set(src.fRight, src.fBottom);\r
- srcPts[3].set(src.fLeft, src.fBottom);\r
- this->mapPoints(dstPts, srcPts, 4);\r
- dst->setBounds(dstPts, 4);\r
-}\r
-\r
-bool GrMatrix::hasPerspective() const {\r
- GrAssert(!!(kPerspective_TypeBit & fTypeMask) ==\r
- (fM[kPersp0] != 0 || fM[kPersp1] != 0 || fM[kPersp2] != gRESCALE));\r
- return 0 != (kPerspective_TypeBit & fTypeMask);\r
-}\r
-\r
-bool GrMatrix::isIdentity() const {\r
- GrAssert((0 == fTypeMask) ==\r
- (GR_Scalar1 == fM[kScaleX] && 0 == fM[kSkewX] && 0 == fM[kTransX] &&\r
- 0 == fM[kSkewY] && GR_Scalar1 == fM[kScaleY] && 0 == fM[kTransY] &&\r
- 0 == fM[kPersp0] && 0 == fM[kPersp1] && gRESCALE == fM[kPersp2]));\r
- return (0 == fTypeMask);\r
-}\r
-\r
-\r
-GrScalar GrMatrix::getMaxStretch() const {\r
-\r
- if (fTypeMask & kPerspective_TypeBit) {\r
- return -GR_Scalar1;\r
- }\r
-\r
- GrScalar stretch;\r
-\r
- if (isIdentity()) {\r
- stretch = GR_Scalar1;\r
- } else if (!(fTypeMask & kSkew_TypeBit)) {\r
- stretch = GrMax(GrScalarAbs(fM[kScaleX]), GrScalarAbs(fM[kScaleY]));\r
- } else if (fTypeMask & kZeroScale_TypeBit) {\r
- stretch = GrMax(GrScalarAbs(fM[kSkewX]), GrScalarAbs(fM[kSkewY]));\r
- } else {\r
- // ignore the translation part of the matrix, just look at 2x2 portion.\r
- // compute singular values, take largest abs value.\r
- // [a b; b c] = A^T*A\r
- GrScalar a = GrMul(fM[kScaleX], fM[kScaleX]) + GrMul(fM[kSkewY], fM[kSkewY]);\r
- GrScalar b = GrMul(fM[kScaleX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kSkewY]);\r
- GrScalar c = GrMul(fM[kSkewX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kScaleY]);\r
- // eigenvalues of A^T*A are the squared singular values of A.\r
- // characteristic equation is det((A^T*A) - l*I) = 0\r
- // l^2 - (a + c)l + (ac-b^2)\r
- // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff\r
- // and roots are guaraunteed to be pos and real).\r
- GrScalar largerRoot;\r
- GrScalar bSqd = GrMul(b,b);\r
- // TODO: fixed point tolerance value.\r
- if (bSqd < 1e-10) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math\r
- largerRoot = GrMax(a, c);\r
- } else {\r
- GrScalar aminusc = a - c;\r
- GrScalar apluscdiv2 = (a + c) / 2;\r
- GrScalar x = sqrtf(GrMul(aminusc,aminusc) + GrMul(4,(bSqd))) / 2;\r
- largerRoot = apluscdiv2 + x;\r
- }\r
-\r
- stretch = sqrtf(largerRoot);\r
- }\r
-#if GR_DEBUG && 0\r
- // test a bunch of vectors. None should be scaled by more than stretch\r
- // (modulo some error) and we should find a vector that is scaled by almost\r
- // stretch.\r
- GrPoint pt;\r
- GrScalar max = 0;\r
- for (int i = 0; i < 1000; ++i) {\r
- GrScalar x = (float)rand() / RAND_MAX;\r
- GrScalar y = sqrtf(1 - (x*x));\r
- pt.fX = fM[kScaleX]*x + fM[kSkewX]*y;\r
- pt.fY = fM[kSkewY]*x + fM[kScaleY]*y;\r
- GrScalar d = pt.distanceToOrigin();\r
- GrAssert(d <= (1.0001 * stretch));\r
- max = GrMax(max, pt.distanceToOrigin());\r
- }\r
- GrAssert((stretch - max) < .05*stretch);\r
-#endif\r
- return stretch;\r
-}\r
-\r
-bool GrMatrix::operator == (const GrMatrix& m) const {\r
- if (fTypeMask != m.fTypeMask) {\r
- return false;\r
- }\r
- if (!fTypeMask) {\r
- return true;\r
- }\r
- for (int i = 0; i < 9; ++i) {\r
- if (m.fM[i] != fM[i]) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool GrMatrix::operator != (const GrMatrix& m) const {\r
- return !(*this == m);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Matrix transformation procs\r
-//////\r
-\r
-void GrMatrix::mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i] = src[i];\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(src[i].fX, fM[kScaleX]);\r
- dst[i].fY = GrMul(src[i].fY, fM[kScaleY]);\r
- }\r
-}\r
-\r
-\r
-void GrMatrix::mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = src[i].fX + fM[kTransX];\r
- dst[i].fY = src[i].fY + fM[kTransY];\r
- }\r
-}\r
-\r
-void GrMatrix::mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + fM[kTransX];\r
- dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + fM[kTransY];\r
- }\r
-}\r
-\r
-void GrMatrix::mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];\r
- dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];\r
- dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];\r
- dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];\r
- dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar x, y, w;\r
- x = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];\r
- y = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];\r
- w = GrMul(fM[kPersp0], src[i].fX) + GrMul(fM[kPersp1], src[i].fY) + fM[kPersp2];\r
- // TODO need fixed point invert\r
- if (w) {\r
- w = 1 / w;\r
- }\r
- dst[i].fX = GrMul(x, w);\r
- dst[i].fY = GrMul(y, w);\r
- }\r
-}\r
-\r
-void GrMatrix::mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- GrAssert(0);\r
-}\r
-\r
-void GrMatrix::mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- memset(dst, 0, sizeof(GrPoint)*count);\r
-}\r
-\r
-void GrMatrix::mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = fM[kTransX];\r
- dst[i].fY = fM[kTransY];\r
- }\r
-}\r
-\r
-void GrMatrix::mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = GrMul(src[i].fY, fM[kSkewX]);\r
- dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-void GrMatrix::mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {\r
- if (src != dst) {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- dst[i].fX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];\r
- dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];\r
- }\r
- } else {\r
- for (uint32_t i = 0; i < count; ++i) {\r
- GrScalar newX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];\r
- dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];\r
- dst[i].fX = newX;\r
- }\r
- }\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-// Unit test\r
-//////\r
-\r
-#include "GrRandom.h"\r
-\r
-#if GR_DEBUG\r
-enum MatrixType {\r
- kRotate_MatrixType,\r
- kScaleX_MatrixType,\r
- kScaleY_MatrixType,\r
- kSkewX_MatrixType,\r
- kSkewY_MatrixType,\r
- kTranslateX_MatrixType,\r
- kTranslateY_MatrixType,\r
- kSwapScaleXY_MatrixType,\r
- kPersp_MatrixType,\r
-\r
- kMatrixTypeCount\r
-};\r
-\r
-static void create_matrix(GrMatrix* matrix, GrRandom& rand) {\r
- MatrixType type = (MatrixType)(rand.nextU() % kMatrixTypeCount);\r
- switch (type) {\r
- case kRotate_MatrixType: {\r
- float angle = rand.nextF() * 2 *3.14159265358979323846f;\r
- GrScalar cosa = GrFloatToScalar(cosf(angle));\r
- GrScalar sina = GrFloatToScalar(sinf(angle));\r
- matrix->setAll(cosa, -sina, 0,\r
- sina, cosa, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kScaleX_MatrixType: {\r
- GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));\r
- matrix->setAll(scale, 0, 0,\r
- 0, GR_Scalar1, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kScaleY_MatrixType: {\r
- GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));\r
- matrix->setAll(GR_Scalar1, 0, 0,\r
- 0, scale, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kSkewX_MatrixType: {\r
- GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));\r
- matrix->setAll(GR_Scalar1, skew, 0,\r
- 0, GR_Scalar1, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kSkewY_MatrixType: {\r
- GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));\r
- matrix->setAll(GR_Scalar1, 0, 0,\r
- skew, GR_Scalar1, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kTranslateX_MatrixType: {\r
- GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));\r
- matrix->setAll(GR_Scalar1, 0, trans,\r
- 0, GR_Scalar1, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kTranslateY_MatrixType: {\r
- GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));\r
- matrix->setAll(GR_Scalar1, 0, 0,\r
- 0, GR_Scalar1, trans,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kSwapScaleXY_MatrixType: {\r
- GrScalar xy = GrFloatToScalar(rand.nextF(-2, 2));\r
- GrScalar yx = GrFloatToScalar(rand.nextF(-2, 2));\r
- matrix->setAll(0, xy, 0,\r
- yx, 0, 0,\r
- 0, 0, GrMatrix::I()[8]);\r
- } break;\r
- case kPersp_MatrixType: {\r
- GrScalar p0 = GrFloatToScalar(rand.nextF(-2, 2));\r
- GrScalar p1 = GrFloatToScalar(rand.nextF(-2, 2));\r
- GrScalar p2 = GrFloatToScalar(rand.nextF(-0.5f, 0.75f));\r
- matrix->setAll(GR_Scalar1, 0, 0,\r
- 0, GR_Scalar1, 0,\r
- p0, p1, GrMul(p2,GrMatrix::I()[8]));\r
- } break;\r
- default:\r
- GrAssert(0);\r
- break;\r
- }\r
-}\r
-#endif\r
-\r
-void GrMatrix::UnitTest() {\r
- GrRandom rand;\r
-\r
- // Create a bunch of matrices and test point mapping, max stretch calc,\r
- // inversion and multiply-by-inverse.\r
-#if GR_DEBUG\r
- for (int i = 0; i < 10000; ++i) {\r
- GrMatrix a, b;\r
- a.setIdentity();\r
- int num = rand.nextU() % 6;\r
- // force testing of I and swapXY\r
- if (0 == i) {\r
- num = 0;\r
- GrAssert(a.isIdentity());\r
- } else if (1 == i) {\r
- num = 0;\r
- a.setAll(0, GR_Scalar1, 0,\r
- GR_Scalar1, 0, 0,\r
- 0, 0, I()[8]);\r
- }\r
- for (int j = 0; j < num; ++j) {\r
- create_matrix(&b, rand);\r
- a.preConcat(b);\r
- }\r
-\r
- GrScalar maxStretch = a.getMaxStretch();\r
- if (maxStretch > 0) {\r
- maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch);\r
- }\r
- GrPoint origin = a.mapPoint(GrPoint(0,0));\r
-\r
- for (int j = 0; j < 9; ++j) {\r
- int mask, origMask = a.fTypeMask;\r
- GrScalar old = a[j];\r
-\r
- a.set(j, GR_Scalar1);\r
- mask = a.fTypeMask;\r
- a.computeTypeMask();\r
- GrAssert(mask == a.fTypeMask);\r
-\r
- a.set(j, 0);\r
- mask = a.fTypeMask;\r
- a.computeTypeMask();\r
- GrAssert(mask == a.fTypeMask);\r
-\r
- a.set(j, 10 * GR_Scalar1);\r
- mask = a.fTypeMask;\r
- a.computeTypeMask();\r
- GrAssert(mask == a.fTypeMask);\r
-\r
- a.set(j, old);\r
- GrAssert(a.fTypeMask == origMask);\r
- }\r
-\r
- for (int j = 0; j < 100; ++j) {\r
- GrPoint pt;\r
- pt.fX = GrFloatToScalar(rand.nextF(-10, 10));\r
- pt.fY = GrFloatToScalar(rand.nextF(-10, 10));\r
-\r
- GrPoint t0, t1, t2;\r
- t0 = a.mapPoint(pt); // map to a new point\r
- t1 = pt;\r
- a.mapPoints(&t1, &t1, 1); // in place\r
- a.mapPerspective(&t2, &pt, 1); // full mult\r
- GrAssert(t0 == t1 && t1 == t2);\r
- if (maxStretch >= 0.f) {\r
- GrVec vec;\r
- vec.setBetween(t0, origin);\r
- GrScalar stretch = vec.length() / pt.distanceToOrigin();\r
- GrAssert(stretch <= maxStretch);\r
- }\r
- }\r
- double det = a.determinant();\r
- if (fabs(det) > 1e-3 && a.invert(&b)) {\r
- GrMatrix c;\r
- c.setConcat(a,b);\r
- for (int i = 0; i < 9; ++i) {\r
- GrScalar diff = GrScalarAbs(c[i] - I()[i]);\r
- GrAssert(diff < (5*GR_Scalar1 / 100));\r
- }\r
- }\r
- }\r
-#endif\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-\r
-int Gr_clz(uint32_t n) {\r
- if (0 == n) {\r
- return 32;\r
- }\r
-\r
- int count = 0;\r
- if (0 == (n & 0xFFFF0000)) {\r
- count += 16;\r
- n <<= 16;\r
- }\r
- if (0 == (n & 0xFF000000)) {\r
- count += 8;\r
- n <<= 8;\r
- }\r
- if (0 == (n & 0xF0000000)) {\r
- count += 4;\r
- n <<= 4;\r
- }\r
- if (0 == (n & 0xC0000000)) {\r
- count += 2;\r
- n <<= 2;\r
- }\r
- if (0 == (n & 0x80000000)) {\r
- count += 1;\r
- }\r
- return count;\r
-}\r
-\r
-///////////////////////////////////////////////////////////////////////////////\r
-#include "GrRect.h"\r
-\r
-void GrRect::setBounds(const GrPoint pts[], int count) {\r
- if (count <= 0) {\r
- this->setEmpty();\r
- } else {\r
- GrScalar L, R, T, B;\r
- L = R = pts[0].fX;\r
- T = B = pts[0].fY;\r
- for (int i = 1; i < count; i++) {\r
- GrScalar x = pts[i].fX;\r
- GrScalar y = pts[i].fY;\r
- if (x < L) {\r
- L = x;\r
- } else if (x > R) {\r
- R = x;\r
- }\r
- if (y < T) {\r
- T = y;\r
- } else if (y > B) {\r
- B = y;\r
- }\r
- }\r
- this->setLTRB(L, T, R, B);\r
- }\r
-}\r
-\r
-\r
-\r
+/*
+ Copyright 2010 Google Inc.
+
+ 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.
+ */
+
+
+#include "GrMatrix.h"
+#include "GrRect.h"
+#include <stddef.h>
+
+#if GR_SCALAR_IS_FLOAT
+ const GrScalar GrMatrix::gRESCALE(GR_Scalar1);
+#else
+ GR_STATIC_ASSERT(GR_SCALAR_IS_FIXED);
+ // fixed point isn't supported right now
+ GR_STATIC_ASSERT(false);
+const GrScalar GrMatrix::gRESCALE(1 << 30);
+#endif
+
+const GrMatrix::MapProc GrMatrix::gMapProcs[] = {
+// Scales are not both zero
+ &GrMatrix::mapIdentity,
+ &GrMatrix::mapScale,
+ &GrMatrix::mapTranslate,
+ &GrMatrix::mapScaleAndTranslate,
+ &GrMatrix::mapSkew,
+ &GrMatrix::mapScaleAndSkew,
+ &GrMatrix::mapSkewAndTranslate,
+ &GrMatrix::mapNonPerspective,
+ // no optimizations for perspective matrices
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapPerspective,
+
+// Scales are zero (every other is invalid because kScale_TypeBit must be set if
+// kZeroScale_TypeBit is set)
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapZero,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapSetToTranslate,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapSwappedScale,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapSwappedScaleAndTranslate,
+
+ // no optimizations for perspective matrices
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapZero,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapPerspective,
+ &GrMatrix::mapInvalid,
+ &GrMatrix::mapPerspective,
+};
+
+void GrMatrix::setIdentity() {
+ fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = 0;
+ fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = 0;
+ fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
+ fTypeMask = 0;
+}
+
+void GrMatrix::setTranslate(GrScalar dx, GrScalar dy) {
+ fM[0] = GR_Scalar1; fM[1] = 0; fM[2] = dx;
+ fM[3] = 0; fM[4] = GR_Scalar1; fM[5] = dy;
+ fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
+ fTypeMask = (0 != dx || 0 != dy) ? kTranslate_TypeBit : 0;
+}
+
+void GrMatrix::setScale(GrScalar sx, GrScalar sy) {
+ fM[0] = sx; fM[1] = 0; fM[2] = 0;
+ fM[3] = 0; fM[4] = sy; fM[5] = 0;
+ fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
+ fTypeMask = (GR_Scalar1 != sx || GR_Scalar1 != sy) ? kScale_TypeBit : 0;
+}
+
+void GrMatrix::setSkew(GrScalar skx, GrScalar sky) {
+ fM[0] = GR_Scalar1; fM[1] = skx; fM[2] = 0;
+ fM[3] = sky; fM[4] = GR_Scalar1; fM[5] = 0;
+ fM[6] = 0; fM[7] = 0; fM[8] = gRESCALE;
+ fTypeMask = (0 != skx || 0 != sky) ? kSkew_TypeBit : 0;
+}
+
+void GrMatrix::setConcat(const GrMatrix& a, const GrMatrix& b) {
+ if (a.isIdentity()) {
+ if (this != &b) {
+ for (int i = 0; i < 9; ++i) {
+ fM[i] = b.fM[i];
+ }
+ fTypeMask = b.fTypeMask;
+ }
+ return;
+ }
+
+ if (b.isIdentity()) {
+ GrAssert(!a.isIdentity());
+ if (this != &a) {
+ for (int i = 0; i < 9; ++i) {
+ fM[i] = a.fM[i];
+ }
+ fTypeMask = a.fTypeMask;
+ }
+ return;
+ }
+
+ // a and/or b could be this
+ GrMatrix tmp;
+
+ // could do more optimizations based on type bits. Hopefully this call is
+ // low frequency.
+ // TODO: make this work for fixed point
+ if (!((b.fTypeMask | a.fTypeMask) & kPerspective_TypeBit)) {
+ tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3];
+ tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4];
+ tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * gRESCALE;
+
+ tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3];
+ tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4];
+ tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * gRESCALE;
+
+ tmp.fM[6] = 0;
+ tmp.fM[7] = 0;
+ tmp.fM[8] = gRESCALE * gRESCALE;
+ } else {
+ tmp.fM[0] = a.fM[0] * b.fM[0] + a.fM[1] * b.fM[3] + a.fM[2] * b.fM[6];
+ tmp.fM[1] = a.fM[0] * b.fM[1] + a.fM[1] * b.fM[4] + a.fM[2] * b.fM[7];
+ tmp.fM[2] = a.fM[0] * b.fM[2] + a.fM[1] * b.fM[5] + a.fM[2] * b.fM[8];
+
+ tmp.fM[3] = a.fM[3] * b.fM[0] + a.fM[4] * b.fM[3] + a.fM[5] * b.fM[6];
+ tmp.fM[4] = a.fM[3] * b.fM[1] + a.fM[4] * b.fM[4] + a.fM[5] * b.fM[7];
+ tmp.fM[5] = a.fM[3] * b.fM[2] + a.fM[4] * b.fM[5] + a.fM[5] * b.fM[8];
+
+ tmp.fM[6] = a.fM[6] * b.fM[0] + a.fM[7] * b.fM[3] + a.fM[8] * b.fM[6];
+ tmp.fM[7] = a.fM[6] * b.fM[1] + a.fM[7] * b.fM[4] + a.fM[8] * b.fM[7];
+ tmp.fM[8] = a.fM[6] * b.fM[2] + a.fM[7] * b.fM[5] + a.fM[8] * b.fM[8];
+ }
+ *this = tmp;
+ this->computeTypeMask();
+}
+
+void GrMatrix::preConcat(const GrMatrix& m) {
+ setConcat(*this, m);
+}
+
+void GrMatrix::postConcat(const GrMatrix& m) {
+ setConcat(m, *this);
+}
+
+double GrMatrix::determinant() const {
+ if (fTypeMask & kPerspective_TypeBit) {
+ return fM[0]*((double)fM[4]*fM[8] - (double)fM[5]*fM[7]) +
+ fM[1]*((double)fM[5]*fM[6] - (double)fM[3]*fM[8]) +
+ fM[2]*((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);
+ } else {
+ return (double)fM[0]*fM[4]*gRESCALE -
+ (double)fM[1]*fM[3]*gRESCALE;
+ }
+}
+
+bool GrMatrix::invert(GrMatrix* inverted) const {
+
+ if (isIdentity()) {
+ if (inverted != this) {
+ inverted->setIdentity();
+ }
+ return true;
+ }
+ static const double MIN_DETERMINANT_SQUARED = 1.e-16;
+
+ // could do more optimizations based on type bits. Hopefully this call is
+ // low frequency.
+
+ double det = determinant();
+
+ // check if we can't be inverted
+ if (det*det <= MIN_DETERMINANT_SQUARED) {
+ return false;
+ } else if (NULL == inverted) {
+ return true;
+ }
+
+ double t[9];
+
+ if (fTypeMask & kPerspective_TypeBit) {
+ t[0] = ((double)fM[4]*fM[8] - (double)fM[5]*fM[7]);
+ t[1] = ((double)fM[2]*fM[7] - (double)fM[1]*fM[8]);
+ t[2] = ((double)fM[1]*fM[5] - (double)fM[2]*fM[4]);
+ t[3] = ((double)fM[5]*fM[6] - (double)fM[3]*fM[8]);
+ t[4] = ((double)fM[0]*fM[8] - (double)fM[2]*fM[6]);
+ t[5] = ((double)fM[2]*fM[3] - (double)fM[0]*fM[5]);
+ t[6] = ((double)fM[3]*fM[7] - (double)fM[4]*fM[6]);
+ t[7] = ((double)fM[1]*fM[6] - (double)fM[0]*fM[7]);
+ t[8] = ((double)fM[0]*fM[4] - (double)fM[1]*fM[3]);
+ det = 1.0 / det;
+ for (int i = 0; i < 9; ++i) {
+ inverted->fM[i] = (GrScalar)(t[i] * det);
+ }
+ } else {
+ t[0] = (double)fM[4]*gRESCALE;
+ t[1] = -(double)fM[1]*gRESCALE;
+ t[2] = (double)fM[1]*fM[5] - (double)fM[2]*fM[4];
+ t[3] = -(double)fM[3]*gRESCALE;
+ t[4] = (double)fM[0]*gRESCALE;
+ t[5] = (double)fM[2]*fM[3] - (double)fM[0]*fM[5];
+ //t[6] = 0.0;
+ //t[7] = 0.0;
+ t[8] = (double)fM[0]*fM[4] - (double)fM[1]*fM[3];
+ det = 1.0 / det;
+ for (int i = 0; i < 6; ++i) {
+ inverted->fM[i] = (GrScalar)(t[i] * det);
+ }
+ inverted->fM[6] = 0;
+ inverted->fM[7] = 0;
+ inverted->fM[8] = (GrScalar)(t[8] * det);
+ }
+ inverted->computeTypeMask();
+ return true;
+}
+
+void GrMatrix::mapRect(GrRect* dst, const GrRect& src) const {
+ GrPoint srcPts[4], dstPts[4];
+ srcPts[0].set(src.fLeft, src.fTop);
+ srcPts[1].set(src.fRight, src.fTop);
+ srcPts[2].set(src.fRight, src.fBottom);
+ srcPts[3].set(src.fLeft, src.fBottom);
+ this->mapPoints(dstPts, srcPts, 4);
+ dst->setBounds(dstPts, 4);
+}
+
+bool GrMatrix::hasPerspective() const {
+ GrAssert(!!(kPerspective_TypeBit & fTypeMask) ==
+ (fM[kPersp0] != 0 || fM[kPersp1] != 0 || fM[kPersp2] != gRESCALE));
+ return 0 != (kPerspective_TypeBit & fTypeMask);
+}
+
+bool GrMatrix::isIdentity() const {
+ GrAssert((0 == fTypeMask) ==
+ (GR_Scalar1 == fM[kScaleX] && 0 == fM[kSkewX] && 0 == fM[kTransX] &&
+ 0 == fM[kSkewY] && GR_Scalar1 == fM[kScaleY] && 0 == fM[kTransY] &&
+ 0 == fM[kPersp0] && 0 == fM[kPersp1] && gRESCALE == fM[kPersp2]));
+ return (0 == fTypeMask);
+}
+
+
+GrScalar GrMatrix::getMaxStretch() const {
+
+ if (fTypeMask & kPerspective_TypeBit) {
+ return -GR_Scalar1;
+ }
+
+ GrScalar stretch;
+
+ if (isIdentity()) {
+ stretch = GR_Scalar1;
+ } else if (!(fTypeMask & kSkew_TypeBit)) {
+ stretch = GrMax(GrScalarAbs(fM[kScaleX]), GrScalarAbs(fM[kScaleY]));
+ } else if (fTypeMask & kZeroScale_TypeBit) {
+ stretch = GrMax(GrScalarAbs(fM[kSkewX]), GrScalarAbs(fM[kSkewY]));
+ } else {
+ // ignore the translation part of the matrix, just look at 2x2 portion.
+ // compute singular values, take largest abs value.
+ // [a b; b c] = A^T*A
+ GrScalar a = GrMul(fM[kScaleX], fM[kScaleX]) + GrMul(fM[kSkewY], fM[kSkewY]);
+ GrScalar b = GrMul(fM[kScaleX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kSkewY]);
+ GrScalar c = GrMul(fM[kSkewX], fM[kSkewX]) + GrMul(fM[kScaleY], fM[kScaleY]);
+ // eigenvalues of A^T*A are the squared singular values of A.
+ // characteristic equation is det((A^T*A) - l*I) = 0
+ // l^2 - (a + c)l + (ac-b^2)
+ // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
+ // and roots are guaraunteed to be pos and real).
+ GrScalar largerRoot;
+ GrScalar bSqd = GrMul(b,b);
+ // TODO: fixed point tolerance value.
+ if (bSqd < 1e-10) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math
+ largerRoot = GrMax(a, c);
+ } else {
+ GrScalar aminusc = a - c;
+ GrScalar apluscdiv2 = (a + c) / 2;
+ GrScalar x = sqrtf(GrMul(aminusc,aminusc) + GrMul(4,(bSqd))) / 2;
+ largerRoot = apluscdiv2 + x;
+ }
+
+ stretch = sqrtf(largerRoot);
+ }
+#if GR_DEBUG && 0
+ // test a bunch of vectors. None should be scaled by more than stretch
+ // (modulo some error) and we should find a vector that is scaled by almost
+ // stretch.
+ GrPoint pt;
+ GrScalar max = 0;
+ for (int i = 0; i < 1000; ++i) {
+ GrScalar x = (float)rand() / RAND_MAX;
+ GrScalar y = sqrtf(1 - (x*x));
+ pt.fX = fM[kScaleX]*x + fM[kSkewX]*y;
+ pt.fY = fM[kSkewY]*x + fM[kScaleY]*y;
+ GrScalar d = pt.distanceToOrigin();
+ GrAssert(d <= (1.0001 * stretch));
+ max = GrMax(max, pt.distanceToOrigin());
+ }
+ GrAssert((stretch - max) < .05*stretch);
+#endif
+ return stretch;
+}
+
+bool GrMatrix::operator == (const GrMatrix& m) const {
+ if (fTypeMask != m.fTypeMask) {
+ return false;
+ }
+ if (!fTypeMask) {
+ return true;
+ }
+ for (int i = 0; i < 9; ++i) {
+ if (m.fM[i] != fM[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool GrMatrix::operator != (const GrMatrix& m) const {
+ return !(*this == m);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Matrix transformation procs
+//////
+
+void GrMatrix::mapIdentity(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i] = src[i];
+ }
+ }
+}
+
+void GrMatrix::mapScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(src[i].fX, fM[kScaleX]);
+ dst[i].fY = GrMul(src[i].fY, fM[kScaleY]);
+ }
+}
+
+
+void GrMatrix::mapTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = src[i].fX + fM[kTransX];
+ dst[i].fY = src[i].fY + fM[kTransY];
+ }
+}
+
+void GrMatrix::mapScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + fM[kTransX];
+ dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + fM[kTransY];
+ }
+}
+
+void GrMatrix::mapSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]);
+ dst[i].fX = newX;
+ }
+ }
+}
+
+void GrMatrix::mapScaleAndSkew(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = GrMul(src[i].fX, fM[kScaleX]) + GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = GrMul(src[i].fY, fM[kScaleY]) + GrMul(src[i].fX, fM[kSkewY]);
+ dst[i].fX = newX;
+ }
+ }
+}
+
+void GrMatrix::mapSkewAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
+ dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = src[i].fX + GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
+ dst[i].fY = src[i].fY + GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
+ dst[i].fX = newX;
+ }
+ }
+}
+
+void GrMatrix::mapNonPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
+ dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
+ dst[i].fY = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
+ dst[i].fX = newX;
+ }
+ }
+}
+
+void GrMatrix::mapPerspective(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar x, y, w;
+ x = GrMul(fM[kScaleX], src[i].fX) + GrMul(fM[kSkewX], src[i].fY) + fM[kTransX];
+ y = GrMul(fM[kSkewY], src[i].fX) + GrMul(fM[kScaleY], src[i].fY) + fM[kTransY];
+ w = GrMul(fM[kPersp0], src[i].fX) + GrMul(fM[kPersp1], src[i].fY) + fM[kPersp2];
+ // TODO need fixed point invert
+ if (w) {
+ w = 1 / w;
+ }
+ dst[i].fX = GrMul(x, w);
+ dst[i].fY = GrMul(y, w);
+ }
+}
+
+void GrMatrix::mapInvalid(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ GrAssert(0);
+}
+
+void GrMatrix::mapZero(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ memset(dst, 0, sizeof(GrPoint)*count);
+}
+
+void GrMatrix::mapSetToTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = fM[kTransX];
+ dst[i].fY = fM[kTransY];
+ }
+}
+
+void GrMatrix::mapSwappedScale(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = GrMul(src[i].fY, fM[kSkewX]);
+ dst[i].fY = GrMul(src[i].fX, fM[kSkewY]);
+ dst[i].fX = newX;
+ }
+ }
+}
+
+void GrMatrix::mapSwappedScaleAndTranslate(GrPoint* dst, const GrPoint* src, uint32_t count) const {
+ if (src != dst) {
+ for (uint32_t i = 0; i < count; ++i) {
+ dst[i].fX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
+ dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
+ }
+ } else {
+ for (uint32_t i = 0; i < count; ++i) {
+ GrScalar newX = GrMul(src[i].fY, fM[kSkewX]) + fM[kTransX];
+ dst[i].fY = GrMul(src[i].fX, fM[kSkewY]) + fM[kTransY];
+ dst[i].fX = newX;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Unit test
+//////
+
+#include "GrRandom.h"
+
+#if GR_DEBUG
+enum MatrixType {
+ kRotate_MatrixType,
+ kScaleX_MatrixType,
+ kScaleY_MatrixType,
+ kSkewX_MatrixType,
+ kSkewY_MatrixType,
+ kTranslateX_MatrixType,
+ kTranslateY_MatrixType,
+ kSwapScaleXY_MatrixType,
+ kPersp_MatrixType,
+
+ kMatrixTypeCount
+};
+
+static void create_matrix(GrMatrix* matrix, GrRandom& rand) {
+ MatrixType type = (MatrixType)(rand.nextU() % kMatrixTypeCount);
+ switch (type) {
+ case kRotate_MatrixType: {
+ float angle = rand.nextF() * 2 *3.14159265358979323846f;
+ GrScalar cosa = GrFloatToScalar(cosf(angle));
+ GrScalar sina = GrFloatToScalar(sinf(angle));
+ matrix->setAll(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kScaleX_MatrixType: {
+ GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
+ matrix->setAll(scale, 0, 0,
+ 0, GR_Scalar1, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kScaleY_MatrixType: {
+ GrScalar scale = GrFloatToScalar(rand.nextF(-2, 2));
+ matrix->setAll(GR_Scalar1, 0, 0,
+ 0, scale, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kSkewX_MatrixType: {
+ GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
+ matrix->setAll(GR_Scalar1, skew, 0,
+ 0, GR_Scalar1, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kSkewY_MatrixType: {
+ GrScalar skew = GrFloatToScalar(rand.nextF(-2, 2));
+ matrix->setAll(GR_Scalar1, 0, 0,
+ skew, GR_Scalar1, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kTranslateX_MatrixType: {
+ GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
+ matrix->setAll(GR_Scalar1, 0, trans,
+ 0, GR_Scalar1, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kTranslateY_MatrixType: {
+ GrScalar trans = GrFloatToScalar(rand.nextF(-10, 10));
+ matrix->setAll(GR_Scalar1, 0, 0,
+ 0, GR_Scalar1, trans,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kSwapScaleXY_MatrixType: {
+ GrScalar xy = GrFloatToScalar(rand.nextF(-2, 2));
+ GrScalar yx = GrFloatToScalar(rand.nextF(-2, 2));
+ matrix->setAll(0, xy, 0,
+ yx, 0, 0,
+ 0, 0, GrMatrix::I()[8]);
+ } break;
+ case kPersp_MatrixType: {
+ GrScalar p0 = GrFloatToScalar(rand.nextF(-2, 2));
+ GrScalar p1 = GrFloatToScalar(rand.nextF(-2, 2));
+ GrScalar p2 = GrFloatToScalar(rand.nextF(-0.5f, 0.75f));
+ matrix->setAll(GR_Scalar1, 0, 0,
+ 0, GR_Scalar1, 0,
+ p0, p1, GrMul(p2,GrMatrix::I()[8]));
+ } break;
+ default:
+ GrAssert(0);
+ break;
+ }
+}
+#endif
+
+void GrMatrix::UnitTest() {
+ GrRandom rand;
+
+ // Create a bunch of matrices and test point mapping, max stretch calc,
+ // inversion and multiply-by-inverse.
+#if GR_DEBUG
+ for (int i = 0; i < 10000; ++i) {
+ GrMatrix a, b;
+ a.setIdentity();
+ int num = rand.nextU() % 6;
+ // force testing of I and swapXY
+ if (0 == i) {
+ num = 0;
+ GrAssert(a.isIdentity());
+ } else if (1 == i) {
+ num = 0;
+ a.setAll(0, GR_Scalar1, 0,
+ GR_Scalar1, 0, 0,
+ 0, 0, I()[8]);
+ }
+ for (int j = 0; j < num; ++j) {
+ create_matrix(&b, rand);
+ a.preConcat(b);
+ }
+
+ GrScalar maxStretch = a.getMaxStretch();
+ if (maxStretch > 0) {
+ maxStretch = GrMul(GR_Scalar1 + GR_Scalar1 / 100, maxStretch);
+ }
+ GrPoint origin = a.mapPoint(GrPoint(0,0));
+
+ for (int j = 0; j < 9; ++j) {
+ int mask, origMask = a.fTypeMask;
+ GrScalar old = a[j];
+
+ a.set(j, GR_Scalar1);
+ mask = a.fTypeMask;
+ a.computeTypeMask();
+ GrAssert(mask == a.fTypeMask);
+
+ a.set(j, 0);
+ mask = a.fTypeMask;
+ a.computeTypeMask();
+ GrAssert(mask == a.fTypeMask);
+
+ a.set(j, 10 * GR_Scalar1);
+ mask = a.fTypeMask;
+ a.computeTypeMask();
+ GrAssert(mask == a.fTypeMask);
+
+ a.set(j, old);
+ GrAssert(a.fTypeMask == origMask);
+ }
+
+ for (int j = 0; j < 100; ++j) {
+ GrPoint pt;
+ pt.fX = GrFloatToScalar(rand.nextF(-10, 10));
+ pt.fY = GrFloatToScalar(rand.nextF(-10, 10));
+
+ GrPoint t0, t1, t2;
+ t0 = a.mapPoint(pt); // map to a new point
+ t1 = pt;
+ a.mapPoints(&t1, &t1, 1); // in place
+ a.mapPerspective(&t2, &pt, 1); // full mult
+ GrAssert(t0 == t1 && t1 == t2);
+ if (maxStretch >= 0.f) {
+ GrVec vec;
+ vec.setBetween(t0, origin);
+ GrScalar stretch = vec.length() / pt.distanceToOrigin();
+ GrAssert(stretch <= maxStretch);
+ }
+ }
+ double det = a.determinant();
+ if (fabs(det) > 1e-3 && a.invert(&b)) {
+ GrMatrix c;
+ c.setConcat(a,b);
+ for (int i = 0; i < 9; ++i) {
+ GrScalar diff = GrScalarAbs(c[i] - I()[i]);
+ GrAssert(diff < (5*GR_Scalar1 / 100));
+ }
+ }
+ }
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int Gr_clz(uint32_t n) {
+ if (0 == n) {
+ return 32;
+ }
+
+ int count = 0;
+ if (0 == (n & 0xFFFF0000)) {
+ count += 16;
+ n <<= 16;
+ }
+ if (0 == (n & 0xFF000000)) {
+ count += 8;
+ n <<= 8;
+ }
+ if (0 == (n & 0xF0000000)) {
+ count += 4;
+ n <<= 4;
+ }
+ if (0 == (n & 0xC0000000)) {
+ count += 2;
+ n <<= 2;
+ }
+ if (0 == (n & 0x80000000)) {
+ count += 1;
+ }
+ return count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#include "GrRect.h"
+
+void GrRect::setBounds(const GrPoint pts[], int count) {
+ if (count <= 0) {
+ this->setEmpty();
+ } else {
+ GrScalar L, R, T, B;
+ L = R = pts[0].fX;
+ T = B = pts[0].fY;
+ for (int i = 1; i < count; i++) {
+ GrScalar x = pts[i].fX;
+ GrScalar y = pts[i].fY;
+ if (x < L) {
+ L = x;
+ } else if (x > R) {
+ R = x;
+ }
+ if (y < T) {
+ T = y;
+ } else if (y > B) {
+ B = y;
+ }
+ }
+ this->setLTRB(L, T, R, B);
+ }
+}
+
+
+