void GrGpu::releaseReservedVertexSpace() { const GeometrySrcState& geoSrc = this->getGeomSrc(); GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc); size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout); fVertexPool->putBack(bytes); --fVertexPoolUseCnt; }
void GrDrawTarget::drawNonIndexed(GrPrimitiveType type, int startVertex, int vertexCount) { #if GR_DEBUG GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); int maxVertex = startVertex + vertexCount; int maxValidVertex; switch (geoSrc.fVertexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw non-indexed geom without vertex src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidVertex = geoSrc.fVertexCount; break; case kBuffer_GeometrySrcType: maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() / VertexSize(geoSrc.fVertexLayout); break; } if (maxVertex > maxValidVertex) { GrCrash("Non-indexed drawing outside valid vertex range."); } #endif if (vertexCount > 0) { this->onDrawNonIndexed(type, startVertex, vertexCount); } }
void VertexArray::RegisterToGPU() { glDeleteVertexArrays(1, &mVAO); glGenVertexArrays(1, &mVAO); mVBO.Init(); mVertexSize = VertexSize(); Bind(); { mVBO.Bind(); int offset = 0; for(const VertexAttribDef &attrib : mVertAttribs) { glEnableVertexAttribArray(attrib.index); glVertexAttribPointer( attrib.index, attrib.size, attrib.type, attrib.normalized, mVertexSize, (void*)offset); offset += attrib.SizeInBytes(); } } UnBind(); }
Mesh::Mesh(const void *vertex_data, int count, int vertex_size, const Attribute *format, vec3 *max_position, vec3 *min_position) : vertex_size_(vertex_size), bone_transforms_(nullptr), bone_global_transforms_(nullptr) { set_format(format); GL_CALL(glGenBuffers(1, &vbo_)); GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo_)); GL_CALL(glBufferData(GL_ARRAY_BUFFER, count * vertex_size, vertex_data, GL_STATIC_DRAW)); // Determine the min and max position if (max_position && min_position) { max_position_ = *max_position; min_position_ = *min_position; } else { auto data = static_cast<const float *>(vertex_data); const Attribute *attribute = format; data += VertexSize(attribute, kPosition3f) / sizeof(float); int step = vertex_size / sizeof(float); min_position_ = vec3(data); max_position_ = min_position_; for (int vertex = 1; vertex < count; vertex++) { data += step; min_position_ = vec3::Min(min_position_, vec3(data)); max_position_ = vec3::Max(max_position_, vec3(data)); } } }
void GrGpu::releaseVertexArray() { // if vertex source was array, we stowed data in the pool const GeometrySrcState& geoSrc = this->getGeomSrc(); GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc); size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout); fVertexPool->putBack(bytes); --fVertexPoolUseCnt; }
bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, int startIndex, int vertexCount, int indexCount) const { const GrDrawState& drawState = this->getDrawState(); #if GR_DEBUG const GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); int maxVertex = startVertex + vertexCount; int maxValidVertex; switch (geoSrc.fVertexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw without vertex src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidVertex = geoSrc.fVertexCount; break; case kBuffer_GeometrySrcType: maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() / VertexSize(geoSrc.fVertexLayout); break; } if (maxVertex > maxValidVertex) { GrCrash("Drawing outside valid vertex range."); } if (indexCount > 0) { int maxIndex = startIndex + indexCount; int maxValidIndex; switch (geoSrc.fIndexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw indexed geom without index src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidIndex = geoSrc.fIndexCount; break; case kBuffer_GeometrySrcType: maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t); break; } if (maxIndex > maxValidIndex) { GrCrash("Index reads outside valid index range."); } } GrAssert(NULL != drawState.getRenderTarget()); for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (drawState.isStageEnabled(s)) { const GrEffect* effect = drawState.getStage(s).getEffect(); int numTextures = effect->numTextures(); for (int t = 0; t < numTextures; ++t) { GrTexture* texture = effect->texture(t); GrAssert(texture->asRenderTarget() != drawState.getRenderTarget()); } } } #endif if (NULL == drawState.getRenderTarget()) { return false; } return true; }
void GrInOrderDrawBuffer::releaseVertexArray() { GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GeometrySrcState& geoSrc = this->getGeomSrc(); size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * geoSrc.fVertexCount; fVertexPool.putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 0; }
void GrInOrderDrawBuffer::releaseReservedVertexSpace() { GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GeometrySrcState& geoSrc = this->getGeomSrc(); GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc); size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * geoSrc.fVertexCount; fVertexPool.putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 0; poolState.fPoolVertexBuffer = 0; }
void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, int startVertex, int vertexCount) { if (!vertexCount) { return; } fCurrQuad = 0; GeometryPoolState& poolState = fGeoPoolStateStack.back(); Draw& draw = fDraws.push_back(); draw.fPrimitiveType = primitiveType; draw.fStartVertex = startVertex; draw.fStartIndex = 0; draw.fVertexCount = vertexCount; draw.fIndexCount = 0; draw.fClipChanged = this->needsNewClip(); if (draw.fClipChanged) { this->pushClip(); } draw.fStateChanged = this->needsNewState(); if (draw.fStateChanged) { this->pushState(); } draw.fVertexLayout = this->getGeomSrc().fVertexLayout; switch (this->getGeomSrc().fVertexSrc) { case kBuffer_GeometrySrcType: draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t vertexBytes = (vertexCount + startVertex) * VertexSize(this->getGeomSrc().fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw.fVertexBuffer = poolState.fPoolVertexBuffer; draw.fStartVertex += poolState.fPoolStartVertex; break; } default: GrCrash("unknown geom src type"); } draw.fVertexBuffer->ref(); draw.fIndexBuffer = NULL; }
void SphereMaterial::CreateVertexBuffer(ID3D11Device* device, Vertex::PosSize* vertices, UINT vertexCount, ID3D11Buffer** vertexBuffer) const { D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc)); vertexBufferDesc.ByteWidth = VertexSize() * vertexCount; vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vertexSubResourceData; ZeroMemory(&vertexSubResourceData, sizeof(vertexSubResourceData)); vertexSubResourceData.pSysMem = vertices; if (FAILED(device->CreateBuffer(&vertexBufferDesc, &vertexSubResourceData, vertexBuffer))) { } }
void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType, int startVertex, int vertexCount) { if (!vertexCount) { return; } this->resetDrawTracking(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); if (this->needsNewClip()) { this->recordClip(); } if (this->needsNewState()) { this->recordState(); } Draw* draw = this->recordDraw(); draw->fPrimitiveType = primitiveType; draw->fStartVertex = startVertex; draw->fStartIndex = 0; draw->fVertexCount = vertexCount; draw->fIndexCount = 0; draw->fVertexLayout = this->getVertexLayout(); switch (this->getGeomSrc().fVertexSrc) { case kBuffer_GeometrySrcType: draw->fVertexBuffer = this->getGeomSrc().fVertexBuffer; break; case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: { size_t vertexBytes = (vertexCount + startVertex) * VertexSize(draw->fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); draw->fVertexBuffer = poolState.fPoolVertexBuffer; draw->fStartVertex += poolState.fPoolStartVertex; break; } default: GrCrash("unknown geom src type"); } draw->fVertexBuffer->ref(); draw->fIndexBuffer = NULL; }
void GrInOrderDrawBuffer::releaseReservedVertexSpace() { GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GeometrySrcState& geoSrc = this->getGeomSrc(); GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc); // When the caller reserved vertex buffer space we gave it back a pointer // provided by the vertex buffer pool. At each draw we tracked the largest // offset into the pool's pointer that was referenced. Now we return to the // pool any portion at the tail of the allocation that no draw referenced. size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) * geoSrc.fVertexCount; fVertexPool.putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 0; poolState.fPoolVertexBuffer = NULL; poolState.fPoolStartVertex = 0; }
void GrInOrderDrawBuffer::geometrySourceWillPop( const GeometrySrcState& restoredState) { GrAssert(fGeoPoolStateStack.count() > 1); fGeoPoolStateStack.pop_back(); GeometryPoolState& poolState = fGeoPoolStateStack.back(); // we have to assume that any slack we had in our vertex/index data // is now unreleasable because data may have been appended later in the // pool. if (kReserved_GeometrySrcType == restoredState.fVertexSrc || kArray_GeometrySrcType == restoredState.fVertexSrc) { poolState.fUsedPoolVertexBytes = VertexSize(restoredState.fVertexLayout) * restoredState.fVertexCount; } if (kReserved_GeometrySrcType == restoredState.fIndexSrc || kArray_GeometrySrcType == restoredState.fIndexSrc) { poolState.fUsedPoolVertexBytes = sizeof(uint16_t) * restoredState.fIndexCount; } }
bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout, void** vertices, void** indices) { GrAssert(!fReservedGeometry.fLocked); size_t reservedVertexSpace = 0; if (fReservedGeometry.fVertexCount) { GrAssert(NULL != vertices); this->prepareVertexPool(); *vertices = fVertexPool->makeSpace(vertexLayout, fReservedGeometry.fVertexCount, &fCurrPoolVertexBuffer, &fCurrPoolStartVertex); if (NULL == *vertices) { return false; } reservedVertexSpace = VertexSize(vertexLayout) * fReservedGeometry.fVertexCount; } if (fReservedGeometry.fIndexCount) { GrAssert(NULL != indices); this->prepareIndexPool(); *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount, &fCurrPoolIndexBuffer, &fCurrPoolStartIndex); if (NULL == *indices) { fVertexPool->putBack(reservedVertexSpace); fCurrPoolVertexBuffer = NULL; return false; } } return true; }
size_t VertexBufferInstance::GetSize() const { return Count() * VertexSize(); }
void GrInOrderDrawBuffer::drawRect(const GrRect& rect, const GrMatrix* matrix, StageBitfield stageEnableBitfield, const GrRect* srcRects[], const GrMatrix* srcMatrices[]) { GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad)); GrAssert(!(fDraws.empty() && fCurrQuad)); GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer)); // if we have a quad IB then either append to the previous run of // rects or start a new run if (fMaxQuads) { bool appendToPreviousDraw = false; GrVertexLayout layout = GetRectVertexLayout(stageEnableBitfield, srcRects); AutoReleaseGeometry geo(this, layout, 4, 0); AutoViewMatrixRestore avmr(this); GrMatrix combinedMatrix = this->getViewMatrix(); this->setViewMatrix(GrMatrix::I()); if (NULL != matrix) { combinedMatrix.preConcat(*matrix); } SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, layout, geo.vertices()); // we don't want to miss an opportunity to batch rects together // simply because the clip has changed if the clip doesn't affect // the rect. bool disabledClip = false; if (this->isClipState() && fClip.isRect()) { GrRect clipRect = fClip.getRect(0); // If the clip rect touches the edge of the viewport, extended it // out (close) to infinity to avoid bogus intersections. // We might consider a more exact clip to viewport if this // conservative test fails. const GrRenderTarget* target = this->getRenderTarget(); if (0 >= clipRect.fLeft) { clipRect.fLeft = GR_ScalarMin; } if (target->width() <= clipRect.fRight) { clipRect.fRight = GR_ScalarMax; } if (0 >= clipRect.top()) { clipRect.fTop = GR_ScalarMin; } if (target->height() <= clipRect.fBottom) { clipRect.fBottom = GR_ScalarMax; } int stride = VertexSize(layout); bool insideClip = true; for (int v = 0; v < 4; ++v) { const GrPoint& p = *GetVertexPoint(geo.vertices(), v, stride); if (!clipRect.contains(p)) { insideClip = false; break; } } if (insideClip) { this->disableState(kClip_StateBit); disabledClip = true; } } if (!needsNewClip() && !needsNewState() && fCurrQuad > 0 && fCurrQuad < fMaxQuads && layout == fLastRectVertexLayout) { int vsize = VertexSize(layout); Draw& lastDraw = fDraws.back(); GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer); GrAssert(kTriangles_PrimitiveType == lastDraw.fPrimitiveType); GrAssert(0 == lastDraw.fVertexCount % 4); GrAssert(0 == lastDraw.fIndexCount % 6); GrAssert(0 == lastDraw.fStartIndex); GeometryPoolState& poolState = fGeoPoolStateStack.back(); bool clearSinceLastDraw = fClears.count() && fClears.back().fBeforeDrawIdx == fDraws.count(); appendToPreviousDraw = !clearSinceLastDraw && lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer && (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex; if (appendToPreviousDraw) { lastDraw.fVertexCount += 4; lastDraw.fIndexCount += 6; fCurrQuad += 1; // we reserved above, so we should be the first // use of this vertex reserveation. GrAssert(0 == poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 4 * vsize; } } if (!appendToPreviousDraw) { this->setIndexSourceToBuffer(fQuadIndexBuffer); drawIndexed(kTriangles_PrimitiveType, 0, 0, 4, 6); fCurrQuad = 1; fLastRectVertexLayout = layout; } if (disabledClip) { this->enableState(kClip_StateBit); } } else { INHERITED::drawRect(rect, matrix, stageEnableBitfield, srcRects, srcMatrices); } }
void GrDrawTarget::VertexLayoutUnitTest() { // not necessarily exhaustive static bool run; if (!run) { run = true; for (int s = 0; s < kNumStages; ++s) { GrAssert(!VertexUsesStage(s, 0)); GrAssert(-1 == VertexStageCoordOffset(s, 0)); GrVertexLayout stageMask = 0; for (int t = 0; t < kMaxTexCoords; ++t) { stageMask |= StageTexCoordVertexLayoutBit(s,t); } GrAssert(1 == kMaxTexCoords || !check_layout(stageMask)); GrAssert(stage_tex_coord_mask(s) == stageMask); stageMask |= StagePosAsTexCoordVertexLayoutBit(s); GrAssert(stage_mask(s) == stageMask); GrAssert(!check_layout(stageMask)); } for (int t = 0; t < kMaxTexCoords; ++t) { GrVertexLayout tcMask = 0; GrAssert(!VertexUsesTexCoordIdx(t, 0)); for (int s = 0; s < kNumStages; ++s) { tcMask |= StageTexCoordVertexLayoutBit(s,t); GrAssert(VertexUsesStage(s, tcMask)); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); GrAssert(VertexUsesTexCoordIdx(t, tcMask)); GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask)); GrAssert(t == VertexTexCoordsForStage(s, tcMask)); for (int s2 = s + 1; s2 < kNumStages; ++s2) { GrAssert(-1 == VertexStageCoordOffset(s2, tcMask)); GrAssert(!VertexUsesStage(s2, tcMask)); GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask)); #if GR_DEBUG GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2); #endif GrAssert(0 == VertexStageCoordOffset(s2, posAsTex)); GrAssert(VertexUsesStage(s2, posAsTex)); GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex)); GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex)); GrAssert(-1 == VertexEdgeOffset(posAsTex)); } GrAssert(-1 == VertexEdgeOffset(tcMask)); GrAssert(-1 == VertexColorOffset(tcMask)); GrAssert(-1 == VertexCoverageOffset(tcMask)); #if GR_DEBUG GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit; #endif GrAssert(-1 == VertexCoverageOffset(withColor)); GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor)); #if GR_DEBUG GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withEdge)); GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge)); GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge)); #if GR_DEBUG GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge)); GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge)); #if GR_DEBUG GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage)); #if GR_DEBUG GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit | kColor_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor)); } GrAssert(tex_coord_idx_mask(t) == tcMask); GrAssert(check_layout(tcMask)); int stageOffsets[kNumStages]; int colorOffset; int edgeOffset; int coverageOffset; int size; size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset, &coverageOffset, &edgeOffset); GrAssert(2*sizeof(GrPoint) == size); GrAssert(-1 == colorOffset); GrAssert(-1 == coverageOffset); GrAssert(-1 == edgeOffset); for (int s = 0; s < kNumStages; ++s) { GrAssert(VertexUsesStage(s, tcMask)); GrAssert(sizeof(GrPoint) == stageOffsets[s]); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); } } } }
void GrInOrderDrawBuffer::drawRect(const GrRect& rect, const SkMatrix* matrix, const GrRect* srcRects[], const SkMatrix* srcMatrices[]) { GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad)); GrAssert(!(fDraws.empty() && fCurrQuad)); GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer)); GrDrawState* drawState = this->drawState(); // if we have a quad IB then either append to the previous run of // rects or start a new run if (fMaxQuads) { bool appendToPreviousDraw = false; GrVertexLayout layout = GetRectVertexLayout(srcRects); // Batching across colors means we move the draw color into the // rect's vertex colors to allow greater batching (a lot of rects // in a row differing only in color is a common occurence in tables). bool batchAcrossColors = true; if (!this->getCaps().dualSourceBlendingSupport()) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (this->getDrawState().isStageEnabled(s)) { // We disable batching across colors when there is a texture // present because (by pushing the the color to the vertices) // Ganesh loses track of the rect's opacity. This, in turn, can // cause some of the blending optimizations to be disabled. This // becomes a huge problem on some of the smaller devices where // shader derivatives and dual source blending aren't supported. // In those cases paths are often drawn to a texture and then // drawn as a texture (using this method). Because dual source // blending is disabled (and the blend optimizations are short // circuited) some of the more esoteric blend modes can no longer // be supported. // TODO: add tracking of batchAcrossColors's opacity batchAcrossColors = false; break; } } } if (batchAcrossColors) { layout |= kColor_VertexLayoutBit; } AutoReleaseGeometry geo(this, layout, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } SkMatrix combinedMatrix = drawState->getViewMatrix(); // We go to device space so that matrix changes allow us to concat // rect draws. When the caller has provided explicit source rects // then we don't want to modify the stages' matrices. Otherwise // we have to account for the view matrix change in the stage // matrices. uint32_t explicitCoordMask = 0; if (srcRects) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (srcRects[s]) { explicitCoordMask |= (1 << s); } } } GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask); if (!adcd.succeeded()) { return; } if (NULL != matrix) { combinedMatrix.preConcat(*matrix); } SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, this->getDrawState().getColor(), layout, geo.vertices()); // Now that the paint's color is stored in the vertices set it to // white so that the following code can batch all the rects regardless // of paint color GrDrawState::AutoColorRestore acr(this->drawState(), batchAcrossColors ? SK_ColorWHITE : this->getDrawState().getColor()); // we don't want to miss an opportunity to batch rects together // simply because the clip has changed if the clip doesn't affect // the rect. bool disabledClip = false; if (drawState->isClipState()) { GrRect devClipRect; bool isIntersectionOfRects = false; fClip->fClipStack->getConservativeBounds(-fClip->fOrigin.fX, -fClip->fOrigin.fY, drawState->getRenderTarget()->width(), drawState->getRenderTarget()->height(), &devClipRect, &isIntersectionOfRects); if (isIntersectionOfRects) { // If the clip rect touches the edge of the viewport, extended it // out (close) to infinity to avoid bogus intersections. // We might consider a more exact clip to viewport if this // conservative test fails. const GrRenderTarget* target = drawState->getRenderTarget(); if (0 >= devClipRect.fLeft) { devClipRect.fLeft = SK_ScalarMin; } if (target->width() <= devClipRect.fRight) { devClipRect.fRight = SK_ScalarMax; } if (0 >= devClipRect.top()) { devClipRect.fTop = SK_ScalarMin; } if (target->height() <= devClipRect.fBottom) { devClipRect.fBottom = SK_ScalarMax; } int stride = VertexSize(layout); bool insideClip = true; for (int v = 0; v < 4; ++v) { const GrPoint& p = *GetVertexPoint(geo.vertices(), v, stride); if (!devClipRect.contains(p)) { insideClip = false; break; } } if (insideClip) { drawState->disableState(GrDrawState::kClip_StateBit); disabledClip = true; } } } if (!this->needsNewClip() && !this->needsNewState() && fCurrQuad > 0 && fCurrQuad < fMaxQuads && layout == fLastRectVertexLayout) { int vsize = VertexSize(layout); Draw& lastDraw = fDraws.back(); GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer); GrAssert(kTriangles_GrPrimitiveType == lastDraw.fPrimitiveType); GrAssert(0 == lastDraw.fVertexCount % 4); GrAssert(0 == lastDraw.fIndexCount % 6); GrAssert(0 == lastDraw.fStartIndex); GeometryPoolState& poolState = fGeoPoolStateStack.back(); appendToPreviousDraw = kDraw_Cmd == fCmds.back() && lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer && (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex; if (appendToPreviousDraw) { lastDraw.fVertexCount += 4; lastDraw.fIndexCount += 6; fCurrQuad += 1; // we reserved above, so we should be the first // use of this vertex reservation. GrAssert(0 == poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 4 * vsize; } } if (!appendToPreviousDraw) { this->setIndexSourceToBuffer(fQuadIndexBuffer); this->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6); fCurrQuad = 1; fLastRectVertexLayout = layout; } if (disabledClip) { drawState->enableState(GrDrawState::kClip_StateBit); } fInstancedDrawTracker.reset(); } else { INHERITED::drawRect(rect, matrix, srcRects, srcMatrices); } }
void GrDrawTarget::VertexLayoutUnitTest() { // Ensure that our globals mask arrays are correct GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages]; GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords]; gen_mask_arrays(stageTexCoordMasks, texCoordMasks); for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrAssert(stageTexCoordMasks[s] == gStageTexCoordMasks[s]); } for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { GrAssert(texCoordMasks[t] == gTexCoordMasks[t]); } // not necessarily exhaustive static bool run; if (!run) { run = true; for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrVertexLayout stageMask = 0; for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { stageMask |= StageTexCoordVertexLayoutBit(s,t); } GrAssert(1 == GrDrawState::kMaxTexCoords || !check_layout(stageMask)); GrAssert(gStageTexCoordMasks[s] == stageMask); GrAssert(!check_layout(stageMask)); } for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { GrVertexLayout tcMask = 0; GrAssert(!VertexUsesTexCoordIdx(t, 0)); for (int s = 0; s < GrDrawState::kNumStages; ++s) { tcMask |= StageTexCoordVertexLayoutBit(s,t); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); GrAssert(VertexUsesTexCoordIdx(t, tcMask)); GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask)); GrAssert(t == VertexTexCoordsForStage(s, tcMask)); for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) { GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask)); #if GR_DEBUG GrVertexLayout posAsTex = tcMask; #endif GrAssert(0 == VertexStageCoordOffset(s2, posAsTex)); GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex)); GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex)); GrAssert(-1 == VertexEdgeOffset(posAsTex)); } GrAssert(-1 == VertexEdgeOffset(tcMask)); GrAssert(-1 == VertexColorOffset(tcMask)); GrAssert(-1 == VertexCoverageOffset(tcMask)); #if GR_DEBUG GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit; #endif GrAssert(-1 == VertexCoverageOffset(withColor)); GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor)); #if GR_DEBUG GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withEdge)); GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge)); GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge)); #if GR_DEBUG GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge)); GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge)); #if GR_DEBUG GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage)); #if GR_DEBUG GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit | kColor_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor)); } GrAssert(gTexCoordMasks[t] == tcMask); GrAssert(check_layout(tcMask)); int stageOffsets[GrDrawState::kNumStages]; int colorOffset; int edgeOffset; int coverageOffset; int size; size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset, &coverageOffset, &edgeOffset); GrAssert(2*sizeof(GrPoint) == size); GrAssert(-1 == colorOffset); GrAssert(-1 == coverageOffset); GrAssert(-1 == edgeOffset); for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrAssert(sizeof(GrPoint) == stageOffsets[s]); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); } } } }
bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, int startIndex, int vertexCount, int indexCount) const { #if GR_DEBUG const GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); int maxVertex = startVertex + vertexCount; int maxValidVertex; switch (geoSrc.fVertexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw without vertex src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidVertex = geoSrc.fVertexCount; break; case kBuffer_GeometrySrcType: maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() / VertexSize(geoSrc.fVertexLayout); break; } if (maxVertex > maxValidVertex) { GrCrash("Drawing outside valid vertex range."); } if (indexCount > 0) { int maxIndex = startIndex + indexCount; int maxValidIndex; switch (geoSrc.fIndexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw indexed geom without index src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidIndex = geoSrc.fIndexCount; break; case kBuffer_GeometrySrcType: maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t); break; } if (maxIndex > maxValidIndex) { GrCrash("Index reads outside valid index range."); } } GrAssert(NULL != this->getDrawState().getRenderTarget()); for (int i = 0; i < GrDrawState::kNumStages; ++i) { if (this->getDrawState().getTexture(i)) { GrAssert(this->getDrawState().getTexture(i)->asRenderTarget() != this->getDrawState().getRenderTarget()); } } #endif const GrDrawState& drawState = this->getDrawState(); if (NULL == drawState.getRenderTarget()) { return false; } if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) { if (kOne_BlendCoeff != drawState.getSrcBlendCoeff() || kZero_BlendCoeff != drawState.getDstBlendCoeff()) { return false; } } for (int s = 0; s < GrDrawState::kNumStages; ++s) { // We don't support using unpremultiplied textures with filters (other // than nearest). Alpha-premulling is not distributive WRT to filtering. // We'd have to filter each texel before filtering. We could do this for // our custom filters but we would also have to disable bilerp and do // a custom bilerp in the shader. Until Skia itself supports unpremul // configs there is no pressure to implement this. if (this->isStageEnabled(s) && GrPixelConfigIsUnpremultiplied(drawState.getTexture(s)->config()) && GrSamplerState::kNearest_Filter != drawState.getSampler(s).getFilter()) { return false; } } return true; }
void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type, int instanceCount, int verticesPerInstance, int indicesPerInstance) { if (!verticesPerInstance || !indicesPerInstance) { return; } const GeometrySrcState& geomSrc = this->getGeomSrc(); // we only attempt to concat the case when reserved verts are used with // an index buffer. if (kReserved_GeometrySrcType == geomSrc.fVertexSrc && kBuffer_GeometrySrcType == geomSrc.fIndexSrc) { Draw* draw = NULL; // if the last draw used the same indices/vertices per shape then we // may be able to append to it. if (verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance && indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) { GrAssert(fDraws.count()); draw = &fDraws.back(); } bool clipChanged = this->needsNewClip(); bool stateChanged = this->needsNewState(); if (clipChanged) { this->pushClip(); } if (stateChanged) { this->pushState(); } GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; // Check whether the draw is compatible with this draw in order to // append if (NULL == draw || clipChanged || stateChanged || draw->fIndexBuffer != geomSrc.fIndexBuffer || draw->fPrimitiveType != type || draw->fVertexBuffer != vertexBuffer) { draw = &fDraws.push_back(); draw->fClipChanged = clipChanged; draw->fStateChanged = stateChanged; draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fPrimitiveType = type; draw->fStartIndex = 0; draw->fIndexCount = 0; draw->fStartVertex = poolState.fPoolStartVertex; draw->fVertexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; } else { GrAssert(!(draw->fIndexCount % indicesPerInstance)); GrAssert(!(draw->fVertexCount % verticesPerInstance)); GrAssert(poolState.fPoolStartVertex == draw->fStartVertex + draw->fVertexCount); } // how many instances can be in a single draw int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance; if (!maxInstancesPerDraw) { return; } // how many instances should be concat'ed onto draw int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount / verticesPerInstance; if (maxInstancesPerDraw > instanceCount) { maxInstancesPerDraw = instanceCount; if (instancesToConcat > instanceCount) { instancesToConcat = instanceCount; } } // update the amount of reserved data actually referenced in draws size_t vertexBytes = instanceCount * verticesPerInstance * VertexSize(draw->fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); while (instanceCount) { if (!instancesToConcat) { int startVertex = draw->fStartVertex + draw->fVertexCount; draw = &fDraws.push_back(); draw->fClipChanged = false; draw->fStateChanged = false; draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fPrimitiveType = type; draw->fStartIndex = 0; draw->fStartVertex = startVertex; draw->fVertexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; instancesToConcat = maxInstancesPerDraw; } draw->fVertexCount += instancesToConcat * verticesPerInstance; draw->fIndexCount += instancesToConcat * indicesPerInstance; instanceCount -= instancesToConcat; instancesToConcat = 0; } // update draw tracking for next draw fCurrQuad = 0; fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance; fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance; } else { this->INHERITED::drawIndexedInstances(type, instanceCount, verticesPerInstance, indicesPerInstance); } }