aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'gpu')
-rw-r--r--gpu/include/GrContext.h996
-rw-r--r--gpu/include/GrContext_impl.h270
-rw-r--r--gpu/include/GrDrawTarget.h6
-rw-r--r--gpu/include/GrGeometryBuffer.h232
-rw-r--r--gpu/include/GrPaint.h206
-rw-r--r--gpu/src/GrContext.cpp1584
-rw-r--r--gpu/src/GrGLUtil.cpp510
-rw-r--r--gpu/src/GrMatrix.cpp1458
8 files changed, 2631 insertions, 2631 deletions
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index 9df7105451..caba6efcec 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -1,498 +1,498 @@
-/*
- 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"
+/*
+ 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"
diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h
index c0a2107a87..fdcb2b1db0 100644
--- a/gpu/include/GrContext_impl.h
+++ b/gpu/include/GrContext_impl.h
@@ -1,135 +1,135 @@
-/*
- 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
+/*
+ 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
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index 929b9ff39b..10c6d48462 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -210,9 +210,9 @@ public:
* @param stage the stage of the sampler to set
* @param matrix the matrix to concat
*/
- void preConcatSamplerMatrix(int stage, const GrMatrix& matrix) {
- GrAssert(stage >= 0 && stage < kNumStages);
- fCurrDrawState.fSamplerStates[stage].preConcatMatrix(matrix);
+ void preConcatSamplerMatrix(int stage, const GrMatrix& matrix) {
+ GrAssert(stage >= 0 && stage < kNumStages);
+ fCurrDrawState.fSamplerStates[stage].preConcatMatrix(matrix);
}
/**
diff --git a/gpu/include/GrGeometryBuffer.h b/gpu/include/GrGeometryBuffer.h
index af6eed5f63..1447e73185 100644
--- a/gpu/include/GrGeometryBuffer.h
+++ b/gpu/include/GrGeometryBuffer.h
@@ -1,116 +1,116 @@
-/*
- 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
+/*
+ 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
diff --git a/gpu/include/GrPaint.h b/gpu/include/GrPaint.h
index a34cbaf445..9402209780 100644
--- a/gpu/include/GrPaint.h
+++ b/gpu/include/GrPaint.h
@@ -1,103 +1,103 @@
-/*
- 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
+/*
+ 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
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index dbc7f6ce18..d14f3743e6 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -1,792 +1,792 @@
-/*
- 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();
-}
+/*
+ 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();
+}
diff --git a/gpu/src/GrGLUtil.cpp b/gpu/src/GrGLUtil.cpp
index f531a6b419..e128d353f0 100644
--- a/gpu/src/GrGLUtil.cpp
+++ b/gpu/src/GrGLUtil.cpp
@@ -1,255 +1,255 @@
-/*
- 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);
+/*
+ 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);
diff --git a/gpu/src/GrMatrix.cpp b/gpu/src/GrMatrix.cpp
index ee2067900d..0a2d1b2b55 100644
--- a/gpu/src/GrMatrix.cpp
+++ b/gpu/src/GrMatrix.cpp
@@ -1,729 +1,729 @@
-/*
- 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);
- }
-}
-
-
-
+/*
+ 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);
+ }
+}
+
+
+