| /* |
| 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 "GrInOrderDrawBuffer.h" |
| #include "GrTexture.h" |
| #include "GrVertexBufferAllocPool.h" |
| #include "GrGpu.h" |
| |
| GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* pool) : |
| fDraws(DRAWS_BLOCK_SIZE, fDrawsStorage), |
| fStates(STATES_BLOCK_SIZE, fStatesStorage), |
| fClips(CLIPS_BLOCK_SIZE, fClipsStorage), |
| fClipChanged(true), |
| fCPUVertices((NULL == pool) ? 0 : VERTEX_BLOCK_SIZE), |
| fBufferVertices(pool), |
| fIndices(INDEX_BLOCK_SIZE), |
| fCurrReservedVertices(NULL), |
| fCurrReservedIndices(NULL), |
| fCurrVertexBuffer(NULL), |
| fReservedVertexBytes(0), |
| fReservedIndexBytes(0), |
| fUsedReservedVertexBytes(0), |
| fUsedReservedIndexBytes(0) { |
| GrAssert(NULL == pool || pool->getGpu()->supportsBufferLocking()); |
| } |
| |
| GrInOrderDrawBuffer::~GrInOrderDrawBuffer() { |
| reset(); |
| } |
| |
| void GrInOrderDrawBuffer::initializeDrawStateAndClip(const GrDrawTarget& target) { |
| this->copyDrawState(target); |
| this->setClip(target.getClip()); |
| } |
| |
| void GrInOrderDrawBuffer::drawIndexed(PrimitiveType type, |
| uint32_t startVertex, |
| uint32_t startIndex, |
| uint32_t vertexCount, |
| uint32_t indexCount) { |
| |
| if (!vertexCount || !indexCount) { |
| return; |
| } |
| |
| Draw& draw = fDraws.push_back(); |
| draw.fType = type; |
| draw.fStartVertex = startVertex; |
| draw.fStartIndex = startIndex; |
| draw.fVertexCount = vertexCount; |
| draw.fIndexCount = indexCount; |
| draw.fClipChanged = grabClip(); |
| draw.fStateChange = grabState(); |
| |
| draw.fVertexLayout = fGeometrySrc.fVertexLayout; |
| switch (fGeometrySrc.fVertexSrc) { |
| case kArray_GeometrySrcType: |
| draw.fUseVertexBuffer = false; |
| draw.fVertexArray = fGeometrySrc.fVertexArray; |
| break; |
| case kReserved_GeometrySrcType: { |
| draw.fUseVertexBuffer = NULL != fBufferVertices; |
| if (draw.fUseVertexBuffer) { |
| draw.fVertexBuffer = fCurrVertexBuffer; |
| draw.fStartVertex += fCurrStartVertex; |
| } else { |
| draw.fVertexArray = fCurrReservedVertices; |
| } |
| size_t vertexBytes = (vertexCount + startVertex) * |
| VertexSize(fGeometrySrc.fVertexLayout); |
| fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes, |
| vertexBytes); |
| } break; |
| case kBuffer_GeometrySrcType: |
| draw.fUseVertexBuffer = true; |
| draw.fVertexBuffer = fGeometrySrc.fVertexBuffer; |
| break; |
| } |
| |
| switch (fGeometrySrc.fIndexSrc) { |
| case kArray_GeometrySrcType: |
| draw.fUseIndexBuffer = false; |
| draw.fIndexArray = fGeometrySrc.fIndexArray; |
| break; |
| case kReserved_GeometrySrcType: { |
| draw.fUseIndexBuffer = false; |
| draw.fIndexArray = fCurrReservedIndices; |
| size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t); |
| fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes); |
| } break; |
| case kBuffer_GeometrySrcType: |
| draw.fUseIndexBuffer = true; |
| draw.fIndexBuffer = fGeometrySrc.fIndexBuffer; |
| break; |
| } |
| } |
| |
| void GrInOrderDrawBuffer::drawNonIndexed(PrimitiveType type, |
| uint32_t startVertex, |
| uint32_t vertexCount) { |
| if (!vertexCount) { |
| return; |
| } |
| |
| Draw& draw = fDraws.push_back(); |
| draw.fType = type; |
| draw.fStartVertex = startVertex; |
| draw.fStartIndex = 0; |
| draw.fVertexCount = vertexCount; |
| draw.fIndexCount = 0; |
| |
| draw.fClipChanged = grabClip(); |
| draw.fStateChange = grabState(); |
| |
| draw.fVertexLayout = fGeometrySrc.fVertexLayout; |
| switch (fGeometrySrc.fVertexSrc) { |
| case kArray_GeometrySrcType: |
| draw.fUseVertexBuffer = false; |
| draw.fVertexArray = fGeometrySrc.fVertexArray; |
| break; |
| case kReserved_GeometrySrcType: { |
| draw.fUseVertexBuffer = NULL != fBufferVertices; |
| if (draw.fUseVertexBuffer) { |
| draw.fVertexBuffer = fCurrVertexBuffer; |
| draw.fStartVertex += fCurrStartVertex; |
| } else { |
| draw.fVertexArray = fCurrReservedVertices; |
| } |
| size_t vertexBytes = (vertexCount + startVertex) * |
| VertexSize(fGeometrySrc.fVertexLayout); |
| fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes, |
| vertexBytes); |
| } break; |
| case kBuffer_GeometrySrcType: |
| draw.fUseVertexBuffer = true; |
| draw.fVertexBuffer = fGeometrySrc.fVertexBuffer; |
| break; |
| } |
| } |
| |
| void GrInOrderDrawBuffer::reset() { |
| GrAssert(!fReservedGeometry.fLocked); |
| uint32_t numStates = fStates.count(); |
| for (uint32_t i = 0; i < numStates; ++i) { |
| for (int s = 0; s < kNumStages; ++s) { |
| GrTexture* tex = accessSavedDrawState(fStates[i]).fTextures[s]; |
| if (NULL != tex) { |
| tex->unref(); |
| } |
| } |
| } |
| fDraws.reset(); |
| fStates.reset(); |
| if (NULL == fBufferVertices) { |
| fCPUVertices.reset(); |
| } else { |
| fBufferVertices->reset(); |
| } |
| fIndices.reset(); |
| fClips.reset(); |
| } |
| |
| void GrInOrderDrawBuffer::playback(GrDrawTarget* target) { |
| GrAssert(NULL != target); |
| GrAssert(target != this); // not considered and why? |
| |
| uint32_t numDraws = fDraws.count(); |
| if (!numDraws) { |
| return; |
| } |
| |
| if (NULL != fBufferVertices) { |
| fBufferVertices->unlock(); |
| } |
| |
| GrDrawTarget::AutoStateRestore asr(target); |
| GrDrawTarget::AutoClipRestore acr(target); |
| // important to not mess with reserve/lock geometry in the target with this |
| // on the stack. |
| GrDrawTarget::AutoGeometrySrcRestore agsr(target); |
| |
| uint32_t currState = ~0; |
| uint32_t currClip = ~0; |
| |
| for (uint32_t i = 0; i < numDraws; ++i) { |
| const Draw& draw = fDraws[i]; |
| if (draw.fStateChange) { |
| ++currState; |
| target->restoreDrawState(fStates[currState]); |
| } |
| if (draw.fClipChanged) { |
| ++currClip; |
| target->setClip(fClips[currClip]); |
| } |
| if (draw.fUseVertexBuffer) { |
| target->setVertexSourceToBuffer(draw.fVertexBuffer, draw.fVertexLayout); |
| } else { |
| target->setVertexSourceToArray(draw.fVertexArray, draw.fVertexLayout); |
| } |
| if (draw.fIndexCount) { |
| if (draw.fUseIndexBuffer) { |
| target->setIndexSourceToBuffer(draw.fIndexBuffer); |
| } else { |
| target->setIndexSourceToArray(draw.fIndexArray); |
| } |
| target->drawIndexed(draw.fType, |
| draw.fStartVertex, |
| draw.fStartIndex, |
| draw.fVertexCount, |
| draw.fIndexCount); |
| } else { |
| target->drawNonIndexed(draw.fType, |
| draw.fStartVertex, |
| draw.fVertexCount); |
| } |
| } |
| } |
| |
| bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout, |
| int32_t* vertexCount, |
| int32_t* indexCount) const { |
| bool flush = false; |
| if (NULL != indexCount) { |
| *indexCount = -1; |
| } |
| if (NULL != vertexCount) { |
| if (NULL != fBufferVertices) { |
| // we will recommend a flush if the verts could fit in a single |
| // preallocated vertex buffer but none are left and it can't fit |
| // in the current VB (which may not be prealloced). |
| if (*vertexCount > fBufferVertices->currentBufferVertices(vertexLayout) && |
| (!fBufferVertices->preallocatedBuffersRemaining() && |
| *vertexCount <= fBufferVertices->preallocatedBufferVertices(vertexLayout))) { |
| |
| flush = true; |
| } |
| *vertexCount = fBufferVertices->currentBufferVertices(vertexLayout); |
| } else { |
| *vertexCount = -1; |
| } |
| } |
| return flush; |
| } |
| |
| bool GrInOrderDrawBuffer::acquireGeometryHelper(GrVertexLayout vertexLayout, |
| void** vertices, |
| void** indices) { |
| if (fReservedGeometry.fVertexCount) { |
| fReservedVertexBytes = VertexSize(vertexLayout) * |
| fReservedGeometry.fVertexCount; |
| if (NULL == fBufferVertices) { |
| fCurrReservedVertices = fCPUVertices.alloc(fReservedVertexBytes); |
| } else { |
| fCurrReservedVertices = fBufferVertices->alloc(vertexLayout, |
| fReservedGeometry.fVertexCount, |
| &fCurrVertexBuffer, |
| &fCurrStartVertex); |
| } |
| if (NULL != vertices) { |
| *vertices = fCurrReservedVertices; |
| } |
| if (NULL == fCurrReservedVertices) { |
| return false; |
| } |
| } |
| if (fReservedGeometry.fIndexCount) { |
| fReservedIndexBytes = sizeof(uint16_t) * fReservedGeometry.fIndexCount; |
| fCurrReservedIndices = fIndices.alloc(fReservedIndexBytes); |
| if (NULL != indices) { |
| *indices = fCurrReservedIndices; |
| } |
| if (NULL == fCurrReservedIndices) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void GrInOrderDrawBuffer::releaseGeometryHelper() { |
| GrAssert(fUsedReservedVertexBytes <= fReservedVertexBytes); |
| GrAssert(fUsedReservedIndexBytes <= fReservedIndexBytes); |
| |
| size_t vertexSlack = fReservedVertexBytes - fUsedReservedVertexBytes; |
| if (NULL == fBufferVertices) { |
| fCPUVertices.release(vertexSlack); |
| } else { |
| fBufferVertices->release(vertexSlack); |
| GR_DEBUGCODE(fCurrVertexBuffer = NULL); |
| GR_DEBUGCODE(fCurrStartVertex = 0); |
| } |
| |
| fIndices.release(fReservedIndexBytes - fUsedReservedIndexBytes); |
| |
| fCurrReservedVertices = NULL; |
| fCurrReservedIndices = NULL; |
| fReservedVertexBytes = 0; |
| fReservedIndexBytes = 0; |
| fUsedReservedVertexBytes = 0; |
| fUsedReservedIndexBytes = 0; |
| } |
| |
| bool GrInOrderDrawBuffer::grabState() { |
| bool newState; |
| if (fStates.empty()) { |
| newState = true; |
| } else { |
| const DrState& old = accessSavedDrawState(fStates.back()); |
| newState = old != fCurrDrawState; |
| } |
| if (newState) { |
| for (int s = 0; s < kNumStages; ++s) { |
| if (NULL != fCurrDrawState.fTextures[s]) { |
| fCurrDrawState.fTextures[s]->ref(); |
| } |
| } |
| saveCurrentDrawState(&fStates.push_back()); |
| } |
| return newState; |
| } |
| |
| bool GrInOrderDrawBuffer::grabClip() { |
| if ((fCurrDrawState.fFlagBits & kClip_StateBit) && |
| (fClipChanged || fClips.empty())) { |
| |
| fClips.push_back() = fClip; |
| fClipChanged = false; |
| return true; |
| } |
| return false; |
| } |
| |
| void GrInOrderDrawBuffer::clipWillChange(const GrClip& clip) { |
| fClipChanged = true; |
| } |
| |