/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrInOrderDrawBuffer_DEFINED #define GrInOrderDrawBuffer_DEFINED #include "GrFlushToGpuDrawTarget.h" #include "GrTargetCommands.h" #include "SkChunkAlloc.h" /** * GrInOrderDrawBuffer is an implementation of GrDrawTarget that queues up draws for eventual * playback into a GrGpu. In theory one draw buffer could playback into another. When index or * vertex buffers are used as geometry sources it is the callers the draw buffer only holds * references to the buffers. It is the callers responsibility to ensure that the data is still * valid when the draw buffer is played back into a GrGpu. Similarly, it is the caller's * responsibility to ensure that all referenced textures, buffers, and render-targets are associated * in the GrGpu object that the buffer is played back into. The buffer requires VB and IB pools to * store geometry. */ class GrInOrderDrawBuffer : public GrFlushToGpuDrawTarget { public: /** * Creates a GrInOrderDrawBuffer * * @param gpu the gpu object that this draw buffer flushes to. * @param vertexPool pool where vertices for queued draws will be saved when * the vertex source is either reserved or array. * @param indexPool pool where indices for queued draws will be saved when * the index source is either reserved or array. */ GrInOrderDrawBuffer(GrGpu* gpu, GrVertexBufferAllocPool* vertexPool, GrIndexBufferAllocPool* indexPool); ~GrInOrderDrawBuffer() override; // tracking for draws DrawToken getCurrentDrawToken() override { return DrawToken(this, fDrawID); } void clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTarget* renderTarget) override; void discard(GrRenderTarget*) override; protected: void willReserveVertexAndIndexSpace(int vertexCount, size_t vertexStride, int indexCount) override; void appendIndicesAndTransforms(const void* indexValues, PathIndexType indexType, const float* transformValues, PathTransformType transformType, int count, char** indicesLocation, float** xformsLocation) { int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType); *indicesLocation = (char*) fPathIndexBuffer.alloc(count * indexBytes, SkChunkAlloc::kThrow_AllocFailType); SkASSERT(SkIsAlign4((uintptr_t)*indicesLocation)); memcpy(*indicesLocation, reinterpret_cast(indexValues), count * indexBytes); const int xformBytes = GrPathRendering::PathTransformSize(transformType) * sizeof(float); *xformsLocation = NULL; if (0 != xformBytes) { *xformsLocation = (float*) fPathTransformBuffer.alloc(count * xformBytes, SkChunkAlloc::kThrow_AllocFailType); SkASSERT(SkIsAlign4((uintptr_t)*xformsLocation)); memcpy(*xformsLocation, transformValues, count * xformBytes); } } bool canConcatToIndexBuffer(const GrIndexBuffer** ib) { const GrDrawTarget::GeometrySrcState& geomSrc = this->getGeomSrc(); // we only attempt to concat when reserved verts are used with a client-specified // index buffer. To make this work with client-specified VBs we'd need to know if the VB // was updated between draws. if (kReserved_GeometrySrcType != geomSrc.fVertexSrc || kBuffer_GeometrySrcType != geomSrc.fIndexSrc) { return false; } *ib = geomSrc.fIndexBuffer; return true; } private: friend class GrTargetCommands; void onReset() override; void onFlush() override; // overrides from GrDrawTarget void onDraw(const GrGeometryProcessor*, const DrawInfo&, const PipelineInfo&) override; void onDrawBatch(GrBatch*, const PipelineInfo&) override; void onDrawRect(GrPipelineBuilder*, GrColor, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix) override; void onStencilPath(const GrPipelineBuilder&, const GrPathProcessor*, const GrPath*, const GrScissorState&, const GrStencilSettings&) override; void onDrawPath(const GrPathProcessor*, const GrPath*, const GrStencilSettings&, const PipelineInfo&) override; void onDrawPaths(const GrPathProcessor*, const GrPathRange*, const void* indices, PathIndexType, const float transformValues[], PathTransformType, int count, const GrStencilSettings&, const PipelineInfo&) override; void onClear(const SkIRect* rect, GrColor color, bool canIgnoreRect, GrRenderTarget* renderTarget) override; bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override; // Attempts to concat instances from info onto the previous draw. info must represent an // instanced draw. The caller must have already recorded a new draw state and clip if necessary. int concatInstancedDraw(const DrawInfo&); // We lazily record clip changes in order to skip clips that have no effect. void recordClipIfNecessary(); // Records any trace markers for a command void recordTraceMarkersIfNecessary(GrTargetCommands::Cmd*); SkString getCmdString(int index) const { SkASSERT(index < fGpuCmdMarkers.count()); return fGpuCmdMarkers[index].toString(); } bool isIssued(uint32_t drawID) override { return drawID != fDrawID; } // TODO: Use a single allocator for commands and records enum { kPathIdxBufferMinReserve = 2 * 64, // 64 uint16_t's kPathXformBufferMinReserve = 2 * 64, // 64 two-float transforms }; GrTargetCommands fCommands; SkTArray fGpuCmdMarkers; SkChunkAlloc fPathIndexBuffer; SkChunkAlloc fPathTransformBuffer; uint32_t fDrawID; typedef GrFlushToGpuDrawTarget INHERITED; }; #endif