michael@0: /* michael@0: * Copyright 2010 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrDrawTarget_DEFINED michael@0: #define GrDrawTarget_DEFINED michael@0: michael@0: #include "GrClipData.h" michael@0: #include "GrDrawState.h" michael@0: #include "GrIndexBuffer.h" michael@0: michael@0: #include "SkClipStack.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkPath.h" michael@0: #include "SkTArray.h" michael@0: #include "SkTLazy.h" michael@0: #include "SkTypes.h" michael@0: #include "SkXfermode.h" michael@0: michael@0: class GrClipData; michael@0: class GrDrawTargetCaps; michael@0: class GrPath; michael@0: class GrVertexBuffer; michael@0: class SkStrokeRec; michael@0: michael@0: class GrDrawTarget : public SkRefCnt { michael@0: protected: michael@0: class DrawInfo; michael@0: michael@0: public: michael@0: SK_DECLARE_INST_COUNT(GrDrawTarget) michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: michael@0: // The context may not be fully constructed and should not be used during GrDrawTarget michael@0: // construction. michael@0: GrDrawTarget(GrContext* context); michael@0: virtual ~GrDrawTarget(); michael@0: michael@0: /** michael@0: * Gets the capabilities of the draw target. michael@0: */ michael@0: const GrDrawTargetCaps* caps() const { return fCaps.get(); } michael@0: michael@0: /** michael@0: * Sets the current clip to the region specified by clip. All draws will be michael@0: * clipped against this clip if kClip_StateBit is enabled. michael@0: * michael@0: * Setting the clip may (or may not) zero out the client's stencil bits. michael@0: * michael@0: * @param description of the clipping region michael@0: */ michael@0: void setClip(const GrClipData* clip); michael@0: michael@0: /** michael@0: * Gets the current clip. michael@0: * michael@0: * @return the clip. michael@0: */ michael@0: const GrClipData* getClip() const; michael@0: michael@0: /** michael@0: * Sets the draw state object for the draw target. Note that this does not michael@0: * make a copy. The GrDrawTarget will take a reference to passed object. michael@0: * Passing NULL will cause the GrDrawTarget to use its own internal draw michael@0: * state object rather than an externally provided one. michael@0: */ michael@0: void setDrawState(GrDrawState* drawState); michael@0: michael@0: /** michael@0: * Read-only access to the GrDrawTarget's current draw state. michael@0: */ michael@0: const GrDrawState& getDrawState() const { return *fDrawState; } michael@0: michael@0: /** michael@0: * Read-write access to the GrDrawTarget's current draw state. Note that michael@0: * this doesn't ref. michael@0: */ michael@0: GrDrawState* drawState() { return fDrawState; } michael@0: michael@0: /** michael@0: * Color alpha and coverage are two inputs to the drawing pipeline. For some michael@0: * blend modes it is safe to fold the coverage into constant or per-vertex michael@0: * color alpha value. For other blend modes they must be handled separately. michael@0: * Depending on features available in the underlying 3D API this may or may michael@0: * not be possible. michael@0: * michael@0: * This function considers the current draw state and the draw target's michael@0: * capabilities to determine whether coverage can be handled correctly. The michael@0: * following assumptions are made: michael@0: * 1. The caller intends to somehow specify coverage. This can be michael@0: * specified either by enabling a coverage stage on the GrDrawState or michael@0: * via the vertex layout. michael@0: * 2. Other than enabling coverage stages or enabling coverage in the michael@0: * layout, the current configuration of the target's GrDrawState is as michael@0: * it will be at draw time. michael@0: */ michael@0: bool canApplyCoverage() const; michael@0: michael@0: /** When we're using coverage AA but the blend is incompatible (given gpu michael@0: * limitations) we should disable AA. */ michael@0: bool shouldDisableCoverageAAForBlend() { michael@0: // Enable below if we should draw with AA even when it produces michael@0: // incorrect blending. michael@0: // return false; michael@0: return !this->canApplyCoverage(); michael@0: } michael@0: michael@0: /** michael@0: * Given the current draw state and hw support, will HW AA lines be used (if michael@0: * a line primitive type is drawn)? michael@0: */ michael@0: bool willUseHWAALines() const; michael@0: michael@0: /** michael@0: * There are three types of "sources" of geometry (vertices and indices) for michael@0: * draw calls made on the target. When performing an indexed draw, the michael@0: * indices and vertices can use different source types. Once a source is michael@0: * specified it can be used for multiple draws. However, the time at which michael@0: * the geometry data is no longer editable depends on the source type. michael@0: * michael@0: * Sometimes it is necessary to perform a draw while upstack code has michael@0: * already specified geometry that it isn't finished with. So there are push michael@0: * and pop methods. This allows the client to push the sources, draw michael@0: * something using alternate sources, and then pop to restore the original michael@0: * sources. michael@0: * michael@0: * Aside from pushes and pops, a source remains valid until another source michael@0: * is set or resetVertexSource / resetIndexSource is called. Drawing from michael@0: * a reset source is an error. michael@0: * michael@0: * The three types of sources are: michael@0: * michael@0: * 1. A cpu array (set*SourceToArray). This is useful when the caller michael@0: * already provided vertex data in a format compatible with a michael@0: * GrVertexLayout. The data in the array is consumed at the time that michael@0: * set*SourceToArray is called and subsequent edits to the array will not michael@0: * be reflected in draws. michael@0: * michael@0: * 2. Reserve. This is most useful when the caller has data it must michael@0: * transform before drawing and is not long-lived. The caller requests michael@0: * that the draw target make room for some amount of vertex and/or index michael@0: * data. The target provides ptrs to hold the vertex and/or index data. michael@0: * michael@0: * The data is writable up until the next drawIndexed, drawNonIndexed, michael@0: * drawIndexedInstances, drawRect, copySurface, or pushGeometrySource. At michael@0: * this point the data is frozen and the ptrs are no longer valid. michael@0: * michael@0: * Where the space is allocated and how it is uploaded to the GPU is michael@0: * subclass-dependent. michael@0: * michael@0: * 3. Vertex and Index Buffers. This is most useful for geometry that will michael@0: * is long-lived. When the data in the buffer is consumed depends on the michael@0: * GrDrawTarget subclass. For deferred subclasses the caller has to michael@0: * guarantee that the data is still available in the buffers at playback. michael@0: * (TODO: Make this more automatic as we have done for read/write pixels) michael@0: * michael@0: * The size of each vertex is determined by querying the current GrDrawState. michael@0: */ michael@0: michael@0: /** michael@0: * Reserves space for vertices and/or indices. Zero can be specifed as michael@0: * either the vertex or index count if the caller desires to only reserve michael@0: * space for only indices or only vertices. If zero is specifed for michael@0: * vertexCount then the vertex source will be unmodified and likewise for michael@0: * indexCount. michael@0: * michael@0: * If the function returns true then the reserve suceeded and the vertices michael@0: * and indices pointers will point to the space created. michael@0: * michael@0: * If the target cannot make space for the request then this function will michael@0: * return false. If vertexCount was non-zero then upon failure the vertex michael@0: * source is reset and likewise for indexCount. michael@0: * michael@0: * The pointers to the space allocated for vertices and indices remain valid michael@0: * until a drawIndexed, drawNonIndexed, drawIndexedInstances, drawRect, michael@0: * copySurface, or push/popGeomtrySource is called. At that point logically a michael@0: * snapshot of the data is made and the pointers are invalid. michael@0: * michael@0: * @param vertexCount the number of vertices to reserve space for. Can be michael@0: * 0. Vertex size is queried from the current GrDrawState. michael@0: * @param indexCount the number of indices to reserve space for. Can be 0. michael@0: * @param vertices will point to reserved vertex space if vertexCount is michael@0: * non-zero. Illegal to pass NULL if vertexCount > 0. michael@0: * @param indices will point to reserved index space if indexCount is michael@0: * non-zero. Illegal to pass NULL if indexCount > 0. michael@0: */ michael@0: bool reserveVertexAndIndexSpace(int vertexCount, michael@0: int indexCount, michael@0: void** vertices, michael@0: void** indices); michael@0: michael@0: /** michael@0: * Provides hints to caller about the number of vertices and indices michael@0: * that can be allocated cheaply. This can be useful if caller is reserving michael@0: * space but doesn't know exactly how much geometry is needed. michael@0: * michael@0: * Also may hint whether the draw target should be flushed first. This is michael@0: * useful for deferred targets. michael@0: * michael@0: * @param vertexCount in: hint about how many vertices the caller would michael@0: * like to allocate. Vertex size is queried from the michael@0: * current GrDrawState. michael@0: * out: a hint about the number of vertices that can be michael@0: * allocated cheaply. Negative means no hint. michael@0: * Ignored if NULL. michael@0: * @param indexCount in: hint about how many indices the caller would michael@0: * like to allocate. michael@0: * out: a hint about the number of indices that can be michael@0: * allocated cheaply. Negative means no hint. michael@0: * Ignored if NULL. michael@0: * michael@0: * @return true if target should be flushed based on the input values. michael@0: */ michael@0: virtual bool geometryHints(int* vertexCount, michael@0: int* indexCount) const; michael@0: michael@0: /** michael@0: * Sets source of vertex data for the next draw. Array must contain michael@0: * the vertex data when this is called. michael@0: * michael@0: * @param vertexArray cpu array containing vertex data. michael@0: * @param vertexCount the number of vertices in the array. Vertex size is michael@0: * queried from the current GrDrawState. michael@0: */ michael@0: void setVertexSourceToArray(const void* vertexArray, int vertexCount); michael@0: michael@0: /** michael@0: * Sets source of index data for the next indexed draw. Array must contain michael@0: * the indices when this is called. michael@0: * michael@0: * @param indexArray cpu array containing index data. michael@0: * @param indexCount the number of indices in the array. michael@0: */ michael@0: void setIndexSourceToArray(const void* indexArray, int indexCount); michael@0: michael@0: /** michael@0: * Sets source of vertex data for the next draw. Data does not have to be michael@0: * in the buffer until drawIndexed, drawNonIndexed, or drawIndexedInstances. michael@0: * michael@0: * @param buffer vertex buffer containing vertex data. Must be michael@0: * unlocked before draw call. Vertex size is queried michael@0: * from current GrDrawState. michael@0: */ michael@0: void setVertexSourceToBuffer(const GrVertexBuffer* buffer); michael@0: michael@0: /** michael@0: * Sets source of index data for the next indexed draw. Data does not have michael@0: * to be in the buffer until drawIndexed. michael@0: * michael@0: * @param buffer index buffer containing indices. Must be unlocked michael@0: * before indexed draw call. michael@0: */ michael@0: void setIndexSourceToBuffer(const GrIndexBuffer* buffer); michael@0: michael@0: /** michael@0: * Resets vertex source. Drawing from reset vertices is illegal. Set vertex michael@0: * source to reserved, array, or buffer before next draw. May be able to free michael@0: * up temporary storage allocated by setVertexSourceToArray or michael@0: * reserveVertexSpace. michael@0: */ michael@0: void resetVertexSource(); michael@0: michael@0: /** michael@0: * Resets index source. Indexed Drawing from reset indices is illegal. Set michael@0: * index source to reserved, array, or buffer before next indexed draw. May michael@0: * be able to free up temporary storage allocated by setIndexSourceToArray michael@0: * or reserveIndexSpace. michael@0: */ michael@0: void resetIndexSource(); michael@0: michael@0: /** michael@0: * Query to find out if the vertex or index source is reserved. michael@0: */ michael@0: bool hasReservedVerticesOrIndices() const { michael@0: return kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc || michael@0: kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc; michael@0: } michael@0: michael@0: /** michael@0: * Pushes and resets the vertex/index sources. Any reserved vertex / index michael@0: * data is finalized (i.e. cannot be updated after the matching pop but can michael@0: * be drawn from). Must be balanced by a pop. michael@0: */ michael@0: void pushGeometrySource(); michael@0: michael@0: /** michael@0: * Pops the vertex / index sources from the matching push. michael@0: */ michael@0: void popGeometrySource(); michael@0: michael@0: /** michael@0: * Draws indexed geometry using the current state and current vertex / index michael@0: * sources. michael@0: * michael@0: * @param type The type of primitives to draw. michael@0: * @param startVertex the vertex in the vertex array/buffer corresponding michael@0: * to index 0 michael@0: * @param startIndex first index to read from index src. michael@0: * @param vertexCount one greater than the max index. michael@0: * @param indexCount the number of index elements to read. The index count michael@0: * is effectively trimmed to the last completely michael@0: * specified primitive. michael@0: * @param devBounds optional bounds hint. This is a promise from the caller, michael@0: * not a request for clipping. michael@0: */ michael@0: void drawIndexed(GrPrimitiveType type, michael@0: int startVertex, michael@0: int startIndex, michael@0: int vertexCount, michael@0: int indexCount, michael@0: const SkRect* devBounds = NULL); michael@0: michael@0: /** michael@0: * Draws non-indexed geometry using the current state and current vertex michael@0: * sources. michael@0: * michael@0: * @param type The type of primitives to draw. michael@0: * @param startVertex the vertex in the vertex array/buffer corresponding michael@0: * to index 0 michael@0: * @param vertexCount one greater than the max index. michael@0: * @param devBounds optional bounds hint. This is a promise from the caller, michael@0: * not a request for clipping. michael@0: */ michael@0: void drawNonIndexed(GrPrimitiveType type, michael@0: int startVertex, michael@0: int vertexCount, michael@0: const SkRect* devBounds = NULL); michael@0: michael@0: /** michael@0: * Draws path into the stencil buffer. The fill must be either even/odd or michael@0: * winding (not inverse or hairline). It will respect the HW antialias flag michael@0: * on the draw state (if possible in the 3D API). michael@0: */ michael@0: void stencilPath(const GrPath*, SkPath::FillType fill); michael@0: michael@0: /** michael@0: * Draws a path. Fill must not be a hairline. It will respect the HW michael@0: * antialias flag on the draw state (if possible in the 3D API). michael@0: */ michael@0: void drawPath(const GrPath*, SkPath::FillType fill); michael@0: michael@0: /** michael@0: * Helper function for drawing rects. It performs a geometry src push and pop michael@0: * and thus will finalize any reserved geometry. michael@0: * michael@0: * @param rect the rect to draw michael@0: * @param matrix optional matrix applied to rect (before viewMatrix) michael@0: * @param localRect optional rect that specifies local coords to map onto michael@0: * rect. If NULL then rect serves as the local coords. michael@0: * @param localMatrix optional matrix applied to localRect. If michael@0: * srcRect is non-NULL and srcMatrix is non-NULL michael@0: * then srcRect will be transformed by srcMatrix. michael@0: * srcMatrix can be NULL when no srcMatrix is desired. michael@0: */ michael@0: void drawRect(const SkRect& rect, michael@0: const SkMatrix* matrix, michael@0: const SkRect* localRect, michael@0: const SkMatrix* localMatrix) { michael@0: AutoGeometryPush agp(this); michael@0: this->onDrawRect(rect, matrix, localRect, localMatrix); michael@0: } michael@0: michael@0: /** michael@0: * Helper for drawRect when the caller doesn't need separate local rects or matrices. michael@0: */ michael@0: void drawSimpleRect(const SkRect& rect, const SkMatrix* matrix = NULL) { michael@0: this->drawRect(rect, matrix, NULL, NULL); michael@0: } michael@0: void drawSimpleRect(const SkIRect& irect, const SkMatrix* matrix = NULL) { michael@0: SkRect rect = SkRect::Make(irect); michael@0: this->drawRect(rect, matrix, NULL, NULL); michael@0: } michael@0: michael@0: /** michael@0: * This call is used to draw multiple instances of some geometry with a michael@0: * given number of vertices (V) and indices (I) per-instance. The indices in michael@0: * the index source must have the form i[k+I] == i[k] + V. Also, all indices michael@0: * i[kI] ... i[(k+1)I-1] must be elements of the range kV ... (k+1)V-1. As a michael@0: * concrete example, the following index buffer for drawing a series of michael@0: * quads each as two triangles each satisfies these conditions with V=4 and michael@0: * I=6: michael@0: * (0,1,2,0,2,3, 4,5,6,4,6,7, 8,9,10,8,10,11, ...) michael@0: * michael@0: * The call assumes that the pattern of indices fills the entire index michael@0: * source. The size of the index buffer limits the number of instances that michael@0: * can be drawn by the GPU in a single draw. However, the caller may specify michael@0: * any (positive) number for instanceCount and if necessary multiple GPU michael@0: * draws will be issued. Moreover, when drawIndexedInstances is called michael@0: * multiple times it may be possible for GrDrawTarget to group them into a michael@0: * single GPU draw. michael@0: * michael@0: * @param type the type of primitives to draw michael@0: * @param instanceCount the number of instances to draw. Each instance michael@0: * consists of verticesPerInstance vertices indexed by michael@0: * indicesPerInstance indices drawn as the primitive michael@0: * type specified by type. michael@0: * @param verticesPerInstance The number of vertices in each instance (V michael@0: * in the above description). michael@0: * @param indicesPerInstance The number of indices in each instance (I michael@0: * in the above description). michael@0: * @param devBounds optional bounds hint. This is a promise from the caller, michael@0: * not a request for clipping. michael@0: */ michael@0: void drawIndexedInstances(GrPrimitiveType type, michael@0: int instanceCount, michael@0: int verticesPerInstance, michael@0: int indicesPerInstance, michael@0: const SkRect* devBounds = NULL); michael@0: michael@0: /** michael@0: * Clear the current render target if one isn't passed in. Ignores the michael@0: * clip and all other draw state (blend mode, stages, etc). Clears the michael@0: * whole thing if rect is NULL, otherwise just the rect. If canIgnoreRect michael@0: * is set then the entire render target can be optionally cleared. michael@0: */ michael@0: virtual void clear(const SkIRect* rect, michael@0: GrColor color, michael@0: bool canIgnoreRect, michael@0: GrRenderTarget* renderTarget = NULL) = 0; michael@0: michael@0: /** michael@0: * instantGpuTraceEvent places a single "sign post" type marker into command stream. The michael@0: * argument marker will be the name of the annotation that is added. michael@0: */ michael@0: void instantGpuTraceEvent(const char* marker); michael@0: /** michael@0: * The following two functions are used for marking groups of commands. Use pushGpuTraceEvent michael@0: * to set the beginning of a command set, and popGpuTraceEvent is be called at end of the michael@0: * command set. The argument marker is the name for the annotation that is added. The push and michael@0: * pops can be used hierarchically, but every push must have a match pop. michael@0: */ michael@0: void pushGpuTraceEvent(const char* marker); michael@0: void popGpuTraceEvent(); michael@0: michael@0: /** michael@0: * Copies a pixel rectangle from one surface to another. This call may finalize michael@0: * reserved vertex/index data (as though a draw call was made). The src pixels michael@0: * copied are specified by srcRect. They are copied to a rect of the same michael@0: * size in dst with top left at dstPoint. If the src rect is clipped by the michael@0: * src bounds then pixel values in the dst rect corresponding to area clipped michael@0: * by the src rect are not overwritten. This method can fail and return false michael@0: * depending on the type of surface, configs, etc, and the backend-specific michael@0: * limitations. If rect is clipped out entirely by the src or dst bounds then michael@0: * true is returned since there is no actual copy necessary to succeed. michael@0: */ michael@0: bool copySurface(GrSurface* dst, michael@0: GrSurface* src, michael@0: const SkIRect& srcRect, michael@0: const SkIPoint& dstPoint); michael@0: /** michael@0: * Function that determines whether a copySurface call would succeed without michael@0: * performing the copy. michael@0: */ michael@0: bool canCopySurface(GrSurface* dst, michael@0: GrSurface* src, michael@0: const SkIRect& srcRect, michael@0: const SkIPoint& dstPoint); michael@0: michael@0: /** michael@0: * This is can be called before allocating a texture to be a dst for copySurface. It will michael@0: * populate the origin, config, and flags fields of the desc such that copySurface is more michael@0: * likely to succeed and be efficient. michael@0: */ michael@0: virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc); michael@0: michael@0: michael@0: /** michael@0: * Release any resources that are cached but not currently in use. This michael@0: * is intended to give an application some recourse when resources are low. michael@0: */ michael@0: virtual void purgeResources() {}; michael@0: michael@0: /** michael@0: * For subclass internal use to invoke a call to onDraw(). See DrawInfo below. michael@0: */ michael@0: void executeDraw(const DrawInfo& info) { this->onDraw(info); } michael@0: michael@0: /** michael@0: * For subclass internal use to invoke a call to onDrawPath(). michael@0: */ michael@0: void executeDrawPath(const GrPath* path, SkPath::FillType fill, michael@0: const GrDeviceCoordTexture* dstCopy) { michael@0: this->onDrawPath(path, fill, dstCopy); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * See AutoStateRestore below. michael@0: */ michael@0: enum ASRInit { michael@0: kPreserve_ASRInit, michael@0: kReset_ASRInit michael@0: }; michael@0: michael@0: /** michael@0: * Saves off the current state and restores it in the destructor. It will michael@0: * install a new GrDrawState object on the target (setDrawState) and restore michael@0: * the previous one in the destructor. The caller should call drawState() to michael@0: * get the new draw state after the ASR is installed. michael@0: * michael@0: * GrDrawState* state = target->drawState(); michael@0: * AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit). michael@0: * state->setRenderTarget(rt); // state refers to the GrDrawState set on michael@0: * // target before asr was initialized. michael@0: * // Therefore, rt is set on the GrDrawState michael@0: * // that will be restored after asr's michael@0: * // destructor rather than target's current michael@0: * // GrDrawState. michael@0: */ michael@0: class AutoStateRestore : public ::SkNoncopyable { michael@0: public: michael@0: /** michael@0: * Default ASR will have no effect unless set() is subsequently called. michael@0: */ michael@0: AutoStateRestore(); michael@0: michael@0: /** michael@0: * Saves the state on target. The state will be restored when the ASR michael@0: * is destroyed. If this constructor is used do not call set(). michael@0: * michael@0: * @param init Should the newly installed GrDrawState be a copy of the michael@0: * previous state or a default-initialized GrDrawState. michael@0: * @param viewMatrix Optional view matrix. If init = kPreserve then the draw state's michael@0: * matrix will be preconcat'ed with the param. All stages will be michael@0: updated to compensate for the matrix change. If init == kReset michael@0: then the draw state's matrix will be this matrix. michael@0: */ michael@0: AutoStateRestore(GrDrawTarget* target, ASRInit init, const SkMatrix* viewMatrix = NULL); michael@0: michael@0: ~AutoStateRestore(); michael@0: michael@0: /** michael@0: * Saves the state on target. The state will be restored when the ASR michael@0: * is destroyed. This should only be called once per ASR object and only michael@0: * when the default constructor was used. For nested saves use multiple michael@0: * ASR objects. michael@0: * michael@0: * @param init Should the newly installed GrDrawState be a copy of the michael@0: * previous state or a default-initialized GrDrawState. michael@0: * @param viewMatrix Optional view matrix. If init = kPreserve then the draw state's michael@0: * matrix will be preconcat'ed with the param. All stages will be michael@0: updated to compensate for the matrix change. If init == kReset michael@0: then the draw state's matrix will be this matrix. michael@0: */ michael@0: void set(GrDrawTarget* target, ASRInit init, const SkMatrix* viewMatrix = NULL); michael@0: michael@0: /** michael@0: * Like set() but makes the view matrix identity. When init is kReset it is as though michael@0: * NULL was passed to set's viewMatrix param. When init is kPreserve it is as though michael@0: * the inverse view matrix was passed. If kPreserve is passed and the draw state's matrix michael@0: * is not invertible then this may fail. michael@0: */ michael@0: bool setIdentity(GrDrawTarget* target, ASRInit init); michael@0: michael@0: private: michael@0: GrDrawTarget* fDrawTarget; michael@0: SkTLazy fTempState; michael@0: GrDrawState* fSavedState; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class AutoReleaseGeometry : public ::SkNoncopyable { michael@0: public: michael@0: AutoReleaseGeometry(GrDrawTarget* target, michael@0: int vertexCount, michael@0: int indexCount); michael@0: AutoReleaseGeometry(); michael@0: ~AutoReleaseGeometry(); michael@0: bool set(GrDrawTarget* target, michael@0: int vertexCount, michael@0: int indexCount); michael@0: bool succeeded() const { return NULL != fTarget; } michael@0: void* vertices() const { SkASSERT(this->succeeded()); return fVertices; } michael@0: void* indices() const { SkASSERT(this->succeeded()); return fIndices; } michael@0: GrPoint* positions() const { michael@0: return static_cast(this->vertices()); michael@0: } michael@0: michael@0: private: michael@0: void reset(); michael@0: michael@0: GrDrawTarget* fTarget; michael@0: void* fVertices; michael@0: void* fIndices; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class AutoClipRestore : public ::SkNoncopyable { michael@0: public: michael@0: AutoClipRestore(GrDrawTarget* target) { michael@0: fTarget = target; michael@0: fClip = fTarget->getClip(); michael@0: } michael@0: michael@0: AutoClipRestore(GrDrawTarget* target, const SkIRect& newClip); michael@0: michael@0: ~AutoClipRestore() { michael@0: fTarget->setClip(fClip); michael@0: } michael@0: private: michael@0: GrDrawTarget* fTarget; michael@0: const GrClipData* fClip; michael@0: SkTLazy fStack; michael@0: GrClipData fReplacementClip; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * Saves the geometry src state at construction and restores in the destructor. It also saves michael@0: * and then restores the vertex attrib state. michael@0: */ michael@0: class AutoGeometryPush : public ::SkNoncopyable { michael@0: public: michael@0: AutoGeometryPush(GrDrawTarget* target) michael@0: : fAttribRestore(target->drawState()) { michael@0: SkASSERT(NULL != target); michael@0: fTarget = target; michael@0: target->pushGeometrySource(); michael@0: } michael@0: michael@0: ~AutoGeometryPush() { fTarget->popGeometrySource(); } michael@0: michael@0: private: michael@0: GrDrawTarget* fTarget; michael@0: GrDrawState::AutoVertexAttribRestore fAttribRestore; michael@0: }; michael@0: michael@0: /** michael@0: * Combination of AutoGeometryPush and AutoStateRestore. The vertex attribs will be in default michael@0: * state regardless of ASRInit value. michael@0: */ michael@0: class AutoGeometryAndStatePush : public ::SkNoncopyable { michael@0: public: michael@0: AutoGeometryAndStatePush(GrDrawTarget* target, michael@0: ASRInit init, michael@0: const SkMatrix* viewMatrix = NULL) michael@0: : fState(target, init, viewMatrix) { michael@0: SkASSERT(NULL != target); michael@0: fTarget = target; michael@0: target->pushGeometrySource(); michael@0: if (kPreserve_ASRInit == init) { michael@0: target->drawState()->setDefaultVertexAttribs(); michael@0: } michael@0: } michael@0: michael@0: ~AutoGeometryAndStatePush() { fTarget->popGeometrySource(); } michael@0: michael@0: private: michael@0: AutoStateRestore fState; michael@0: GrDrawTarget* fTarget; michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: // Draw execution tracking (for font atlases and other resources) michael@0: class DrawToken { michael@0: public: michael@0: DrawToken(GrDrawTarget* drawTarget, uint32_t drawID) : michael@0: fDrawTarget(drawTarget), fDrawID(drawID) {} michael@0: michael@0: bool isIssued() { return NULL != fDrawTarget && fDrawTarget->isIssued(fDrawID); } michael@0: michael@0: private: michael@0: GrDrawTarget* fDrawTarget; michael@0: uint32_t fDrawID; // this may wrap, but we're doing direct comparison michael@0: // so that should be okay michael@0: }; michael@0: michael@0: virtual DrawToken getCurrentDrawToken() { return DrawToken(this, 0); } michael@0: michael@0: protected: michael@0: michael@0: enum GeometrySrcType { michael@0: kNone_GeometrySrcType, //getGeomSrc(); michael@0: switch (src.fIndexSrc) { michael@0: case kNone_GeometrySrcType: michael@0: return 0; michael@0: case kReserved_GeometrySrcType: michael@0: case kArray_GeometrySrcType: michael@0: return src.fIndexCount; michael@0: case kBuffer_GeometrySrcType: michael@0: return static_cast(src.fIndexBuffer->sizeInBytes() / sizeof(uint16_t)); michael@0: default: michael@0: GrCrash("Unexpected Index Source."); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: // This method is called by copySurface The srcRect is guaranteed to be entirely within the michael@0: // src bounds. Likewise, the dst rect implied by dstPoint and srcRect's width and height falls michael@0: // entirely within the dst. The default implementation will draw a rect from the src to the michael@0: // dst if the src is a texture and the dst is a render target and fail otherwise. michael@0: virtual bool onCopySurface(GrSurface* dst, michael@0: GrSurface* src, michael@0: const SkIRect& srcRect, michael@0: const SkIPoint& dstPoint); michael@0: michael@0: // Called to determine whether an onCopySurface call would succeed or not. This is useful for michael@0: // proxy subclasses to test whether the copy would succeed without executing it yet. Derived michael@0: // classes must keep this consistent with their implementation of onCopySurface(). The inputs michael@0: // are the same as onCopySurface(), i.e. srcRect and dstPoint are clipped to be inside the src michael@0: // and dst bounds. michael@0: virtual bool onCanCopySurface(GrSurface* dst, michael@0: GrSurface* src, michael@0: const SkIRect& srcRect, michael@0: const SkIPoint& dstPoint); michael@0: michael@0: GrContext* getContext() { return fContext; } michael@0: const GrContext* getContext() const { return fContext; } michael@0: michael@0: // A subclass may override this function if it wishes to be notified when the clip is changed. michael@0: // The override should call INHERITED::clipWillBeSet(). michael@0: virtual void clipWillBeSet(const GrClipData* clipData); michael@0: michael@0: // subclasses must call this in their destructors to ensure all vertex michael@0: // and index sources have been released (including those held by michael@0: // pushGeometrySource()) michael@0: void releaseGeometry(); michael@0: michael@0: // accessors for derived classes michael@0: const GeometrySrcState& getGeomSrc() const { return fGeoSrcStateStack.back(); } michael@0: // it is preferable to call this rather than getGeomSrc()->fVertexSize because of the assert. michael@0: size_t getVertexSize() const { michael@0: // the vertex layout is only valid if a vertex source has been specified. michael@0: SkASSERT(this->getGeomSrc().fVertexSrc != kNone_GeometrySrcType); michael@0: return this->getGeomSrc().fVertexSize; michael@0: } michael@0: michael@0: // Subclass must initialize this in its constructor. michael@0: SkAutoTUnref fCaps; michael@0: michael@0: /** michael@0: * Used to communicate draws to subclass's onDraw function. michael@0: */ michael@0: class DrawInfo { michael@0: public: michael@0: DrawInfo(const DrawInfo& di) { (*this) = di; } michael@0: DrawInfo& operator =(const DrawInfo& di); michael@0: michael@0: GrPrimitiveType primitiveType() const { return fPrimitiveType; } michael@0: int startVertex() const { return fStartVertex; } michael@0: int startIndex() const { return fStartIndex; } michael@0: int vertexCount() const { return fVertexCount; } michael@0: int indexCount() const { return fIndexCount; } michael@0: int verticesPerInstance() const { return fVerticesPerInstance; } michael@0: int indicesPerInstance() const { return fIndicesPerInstance; } michael@0: int instanceCount() const { return fInstanceCount; } michael@0: michael@0: bool isIndexed() const { return fIndexCount > 0; } michael@0: #ifdef SK_DEBUG michael@0: bool isInstanced() const; // this version is longer because of asserts michael@0: #else michael@0: bool isInstanced() const { return fInstanceCount > 0; } michael@0: #endif michael@0: michael@0: // adds or remove instances michael@0: void adjustInstanceCount(int instanceOffset); michael@0: // shifts the start vertex michael@0: void adjustStartVertex(int vertexOffset); michael@0: // shifts the start index michael@0: void adjustStartIndex(int indexOffset); michael@0: michael@0: void setDevBounds(const SkRect& bounds) { michael@0: fDevBoundsStorage = bounds; michael@0: fDevBounds = &fDevBoundsStorage; michael@0: } michael@0: const SkRect* getDevBounds() const { return fDevBounds; } michael@0: michael@0: // NULL if no copy of the dst is needed for the draw. michael@0: const GrDeviceCoordTexture* getDstCopy() const { michael@0: if (NULL != fDstCopy.texture()) { michael@0: return &fDstCopy; michael@0: } else { michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: DrawInfo() { fDevBounds = NULL; } michael@0: michael@0: friend class GrDrawTarget; michael@0: michael@0: GrPrimitiveType fPrimitiveType; michael@0: michael@0: int fStartVertex; michael@0: int fStartIndex; michael@0: int fVertexCount; michael@0: int fIndexCount; michael@0: michael@0: int fInstanceCount; michael@0: int fVerticesPerInstance; michael@0: int fIndicesPerInstance; michael@0: michael@0: SkRect fDevBoundsStorage; michael@0: SkRect* fDevBounds; michael@0: michael@0: GrDeviceCoordTexture fDstCopy; michael@0: }; michael@0: michael@0: private: michael@0: // A subclass can optionally overload this function to be notified before michael@0: // vertex and index space is reserved. michael@0: virtual void willReserveVertexAndIndexSpace(int vertexCount, int indexCount) {} michael@0: michael@0: // implemented by subclass to allocate space for reserved geom michael@0: virtual bool onReserveVertexSpace(size_t vertexSize, int vertexCount, void** vertices) = 0; michael@0: virtual bool onReserveIndexSpace(int indexCount, void** indices) = 0; michael@0: // implemented by subclass to handle release of reserved geom space michael@0: virtual void releaseReservedVertexSpace() = 0; michael@0: virtual void releaseReservedIndexSpace() = 0; michael@0: // subclass must consume array contents when set michael@0: virtual void onSetVertexSourceToArray(const void* vertexArray, int vertexCount) = 0; michael@0: virtual void onSetIndexSourceToArray(const void* indexArray, int indexCount) = 0; michael@0: // subclass is notified that geom source will be set away from an array michael@0: virtual void releaseVertexArray() = 0; michael@0: virtual void releaseIndexArray() = 0; michael@0: // subclass overrides to be notified just before geo src state is pushed/popped. michael@0: virtual void geometrySourceWillPush() = 0; michael@0: virtual void geometrySourceWillPop(const GeometrySrcState& restoredState) = 0; michael@0: // subclass called to perform drawing michael@0: virtual void onDraw(const DrawInfo&) = 0; michael@0: // Implementation of drawRect. The geometry src and vertex attribs will already michael@0: // be saved before this is called and restored afterwards. A subclass may override michael@0: // this to perform more optimal rect rendering. Its draws should be funneled through michael@0: // one of the public GrDrawTarget draw methods (e.g. drawNonIndexed, michael@0: // drawIndexedInstances, ...). The base class draws a two triangle fan using michael@0: // drawNonIndexed from reserved vertex space. michael@0: virtual void onDrawRect(const SkRect& rect, michael@0: const SkMatrix* matrix, michael@0: const SkRect* localRect, michael@0: const SkMatrix* localMatrix); michael@0: michael@0: virtual void onStencilPath(const GrPath*, SkPath::FillType) = 0; michael@0: virtual void onDrawPath(const GrPath*, SkPath::FillType, michael@0: const GrDeviceCoordTexture* dstCopy) = 0; michael@0: michael@0: virtual void onInstantGpuTraceEvent(const char* marker) = 0; michael@0: virtual void onPushGpuTraceEvent(const char* marker) = 0; michael@0: virtual void onPopGpuTraceEvent() = 0; michael@0: michael@0: // helpers for reserving vertex and index space. michael@0: bool reserveVertexSpace(size_t vertexSize, michael@0: int vertexCount, michael@0: void** vertices); michael@0: bool reserveIndexSpace(int indexCount, void** indices); michael@0: michael@0: // called by drawIndexed and drawNonIndexed. Use a negative indexCount to michael@0: // indicate non-indexed drawing. michael@0: bool checkDraw(GrPrimitiveType type, int startVertex, michael@0: int startIndex, int vertexCount, michael@0: int indexCount) const; michael@0: // called when setting a new vert/idx source to unref prev vb/ib michael@0: void releasePreviousVertexSource(); michael@0: void releasePreviousIndexSource(); michael@0: michael@0: // Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required michael@0: // but couldn't be made. Otherwise, returns true. michael@0: bool setupDstReadIfNecessary(DrawInfo* info) { michael@0: return this->setupDstReadIfNecessary(&info->fDstCopy, info->getDevBounds()); michael@0: } michael@0: bool setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds); michael@0: michael@0: // Check to see if this set of draw commands has been sent out michael@0: virtual bool isIssued(uint32_t drawID) { return true; } michael@0: michael@0: enum { michael@0: kPreallocGeoSrcStateStackCnt = 4, michael@0: }; michael@0: SkSTArray fGeoSrcStateStack; michael@0: const GrClipData* fClip; michael@0: GrDrawState* fDrawState; michael@0: GrDrawState fDefaultDrawState; michael@0: // The context owns us, not vice-versa, so this ptr is not ref'ed by DrawTarget. michael@0: GrContext* fContext; michael@0: // To keep track that we always have at least as many debug marker pushes as pops michael@0: int fPushGpuTraceCount; michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif