From 27847dedd9b5c1f48998c40842f3494c0746257f Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Tue, 22 Feb 2011 20:59:41 +0000 Subject: [PATCH] Fix line endings in Gr files and set svn eol style to LF git-svn-id: http://skia.googlecode.com/svn/trunk@832 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gpu/include/GrContext.h | 996 ++++++++++++------------- gpu/include/GrContext_impl.h | 270 +++---- gpu/include/GrDrawTarget.h | 6 +- gpu/include/GrGeometryBuffer.h | 232 +++--- gpu/include/GrPaint.h | 206 +++--- gpu/src/GrContext.cpp | 1584 ++++++++++++++++++++-------------------- gpu/src/GrGLUtil.cpp | 510 ++++++------- 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 9df7105..caba6ef 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 - 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 - void drawCustomVertices(const GrPaint& paint, - GrPrimitiveType primitiveType, - const POS_SRC& posSrc); - template - void drawCustomVertices(const GrPaint& paint, - GrPrimitiveType primitiveType, - const POS_SRC& posSrc, - const TEX_SRC* texCoordSrc); - template - 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 + 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 + void drawCustomVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + const POS_SRC& posSrc); + template + void drawCustomVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + const POS_SRC& posSrc, + const TEX_SRC* texCoordSrc); + template + 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 c0a2107..fdcb2b1 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 -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 -inline void GrContext::drawCustomVertices(const GrPaint& paint, - GrPrimitiveType primitiveType, - const POS_SRC& posSrc) { - this->drawCustomVertices(paint, primitiveType, posSrc, - NULL, NULL, NULL); -} - -template -inline void GrContext::drawCustomVertices(const GrPaint& paint, - GrPrimitiveType primitiveType, - const POS_SRC& posSrc, - const TEX_SRC* texCoordSrc) { - this->drawCustomVertices(paint, primitiveType, posSrc, - texCoordSrc, NULL, NULL); -} - -template -inline void GrContext::drawCustomVertices(const GrPaint& paint, - GrPrimitiveType primitiveType, - const POS_SRC& posSrc, - const TEX_SRC* texCoordSrc, - const COL_SRC* colorSrc) { - drawCustomVertices(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 +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 +inline void GrContext::drawCustomVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + const POS_SRC& posSrc) { + this->drawCustomVertices(paint, primitiveType, posSrc, + NULL, NULL, NULL); +} + +template +inline void GrContext::drawCustomVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + const POS_SRC& posSrc, + const TEX_SRC* texCoordSrc) { + this->drawCustomVertices(paint, primitiveType, posSrc, + texCoordSrc, NULL, NULL); +} + +template +inline void GrContext::drawCustomVertices(const GrPaint& paint, + GrPrimitiveType primitiveType, + const POS_SRC& posSrc, + const TEX_SRC* texCoordSrc, + const COL_SRC* colorSrc) { + drawCustomVertices(paint, primitiveType, posSrc, + texCoordSrc, colorSrc, NULL); +} + +#endif diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h index 929b9ff..10c6d48 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 af6eed5..1447e73 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 a34cbaf..9402209 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 dbc7f6c..d14f374 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(desc.fWidth, - fGpu->minRenderTargetWidth())); - rtDesc.fHeight = GrNextPow2(GrMax(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(desc.fWidth, + fGpu->minRenderTargetWidth())); + rtDesc.fHeight = GrNextPow2(GrMax(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 f531a6b..e128d35 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 - -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(&(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(&(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 + +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(&(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(&(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 ee20679..0a2d1b2 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 - -#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 + +#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); + } +} + + + -- 2.7.4