/* * 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 "GrDrawTarget.h" #include "GrCommandBuilder.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 GrClipTarget { public: /** * Creates a GrInOrderDrawBuffer * * @param context the context object that owns this draw buffer. */ GrInOrderDrawBuffer(GrContext* context); ~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 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); } } private: friend class GrInOrderCommandBuilder; friend class GrTargetCommands; typedef GrTargetCommands::State State; State* allocState(const GrPrimitiveProcessor* primProc = NULL) { void* allocation = fPipelineBuffer.alloc(sizeof(State), SkChunkAlloc::kThrow_AllocFailType); return SkNEW_PLACEMENT_ARGS(allocation, State, (primProc)); } void unallocState(State* state) { state->unref(); fPipelineBuffer.unalloc(state); } void onReset() override; void onFlush() override; // overrides from GrDrawTarget void onDrawBatch(GrBatch*, const PipelineInfo&) 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; void onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override; // 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; } State* SK_WARN_UNUSED_RESULT setupPipelineAndShouldDraw(const GrPrimitiveProcessor*, const GrDrawTarget::PipelineInfo&); State* SK_WARN_UNUSED_RESULT setupPipelineAndShouldDraw(GrBatch*, const GrDrawTarget::PipelineInfo&); // TODO: Use a single allocator for commands and records enum { kPathIdxBufferMinReserve = 2 * 64, // 64 uint16_t's kPathXformBufferMinReserve = 2 * 64, // 64 two-float transforms kPipelineBufferMinReserve = 32 * sizeof(State), }; // every 100 flushes we should reset our fPipelineBuffer to prevent us from holding at a // highwater mark static const int kPipelineBufferHighWaterMark = 100; SkAutoTDelete fCommands; SkTArray fGpuCmdMarkers; SkChunkAlloc fPathIndexBuffer; SkChunkAlloc fPathTransformBuffer; SkChunkAlloc fPipelineBuffer; uint32_t fDrawID; SkAutoTUnref fPrevState; typedef GrClipTarget INHERITED; }; #endif