diff options
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/include/GrContext.h | 996 | ||||
-rw-r--r-- | gpu/include/GrContext_impl.h | 270 | ||||
-rw-r--r-- | gpu/include/GrDrawTarget.h | 6 | ||||
-rw-r--r-- | gpu/include/GrGeometryBuffer.h | 232 | ||||
-rw-r--r-- | gpu/include/GrPaint.h | 206 | ||||
-rw-r--r-- | gpu/src/GrContext.cpp | 1584 | ||||
-rw-r--r-- | gpu/src/GrGLUtil.cpp | 510 | ||||
-rw-r--r-- | gpu/src/GrMatrix.cpp | 1458 |
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); + } +} + + + |