| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/gpu/gl/GrGLOpsRenderPass.h" |
| |
| #include "src/gpu/GrContextPriv.h" |
| #include "src/gpu/GrFixedClip.h" |
| #include "src/gpu/GrProgramInfo.h" |
| #include "src/gpu/GrRenderTargetPriv.h" |
| |
| void GrGLOpsRenderPass::set(GrRenderTarget* rt, const SkIRect& contentBounds, |
| GrSurfaceOrigin origin, const LoadAndStoreInfo& colorInfo, |
| const StencilLoadAndStoreInfo& stencilInfo) { |
| SkASSERT(fGpu); |
| SkASSERT(!fRenderTarget); |
| SkASSERT(fGpu == rt->getContext()->priv().getGpu()); |
| |
| this->INHERITED::set(rt, origin); |
| fContentBounds = contentBounds; |
| fColorLoadAndStoreInfo = colorInfo; |
| fStencilLoadAndStoreInfo = stencilInfo; |
| } |
| |
| void GrGLOpsRenderPass::onBegin() { |
| fGpu->beginCommandBuffer(fRenderTarget, fContentBounds, fOrigin, fColorLoadAndStoreInfo, |
| fStencilLoadAndStoreInfo); |
| } |
| |
| void GrGLOpsRenderPass::onEnd() { |
| fGpu->endCommandBuffer(fRenderTarget, fColorLoadAndStoreInfo, fStencilLoadAndStoreInfo); |
| } |
| |
| bool GrGLOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, |
| const SkRect& drawBounds) { |
| fPrimitiveType = programInfo.primitiveType(); |
| return fGpu->flushGLState(fRenderTarget, programInfo); |
| } |
| |
| void GrGLOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { |
| fGpu->flushScissorRect(scissor, fRenderTarget->width(), fRenderTarget->height(), fOrigin); |
| } |
| |
| bool GrGLOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc, |
| const GrSurfaceProxy* const primProcTextures[], |
| const GrPipeline& pipeline) { |
| GrGLProgram* program = fGpu->currentProgram(); |
| SkASSERT(program); |
| program->bindTextures(primProc, primProcTextures, pipeline); |
| return true; |
| } |
| |
| void GrGLOpsRenderPass::onBindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer, |
| const GrBuffer* vertexBuffer, |
| GrPrimitiveRestart primitiveRestart) { |
| SkASSERT((primitiveRestart == GrPrimitiveRestart::kNo) || indexBuffer); |
| GrGLProgram* program = fGpu->currentProgram(); |
| SkASSERT(program); |
| |
| int numAttribs = program->numVertexAttributes() + program->numInstanceAttributes(); |
| fAttribArrayState = fGpu->bindInternalVertexArray(indexBuffer, numAttribs, primitiveRestart); |
| |
| if (indexBuffer) { |
| if (indexBuffer->isCpuBuffer()) { |
| auto* cpuIndexBuffer = static_cast<const GrCpuBuffer*>(indexBuffer); |
| fIndexPointer = reinterpret_cast<const uint16_t*>(cpuIndexBuffer->data()); |
| } else { |
| fIndexPointer = nullptr; |
| } |
| } |
| |
| if (!fGpu->glCaps().baseVertexBaseInstanceSupport()) { |
| // This platform does not support baseInstance. Defer binding of the instance buffer. |
| fActiveInstanceBuffer = sk_ref_sp(instanceBuffer); |
| } else { |
| this->bindInstanceBuffer(instanceBuffer, 0); |
| } |
| if (!indexBuffer && fGpu->glCaps().drawArraysBaseVertexIsBroken()) { |
| // There is a driver bug affecting glDrawArrays. Defer binding of the vertex buffer. |
| fActiveVertexBuffer = sk_ref_sp(vertexBuffer); |
| } else if (indexBuffer && !fGpu->glCaps().baseVertexBaseInstanceSupport()) { |
| // This platform does not support baseVertex with indexed draws. Defer binding of the |
| // vertex buffer. |
| fActiveVertexBuffer = sk_ref_sp(vertexBuffer); |
| } else { |
| this->bindVertexBuffer(vertexBuffer, 0); |
| } |
| } |
| |
| void GrGLOpsRenderPass::bindInstanceBuffer(const GrBuffer* instanceBuffer, int baseInstance) { |
| GrGLProgram* program = fGpu->currentProgram(); |
| SkASSERT(program); |
| if (int instanceStride = program->instanceStride()) { |
| SkASSERT(instanceBuffer); |
| SkASSERT(instanceBuffer->isCpuBuffer() || |
| !static_cast<const GrGpuBuffer*>(instanceBuffer)->isMapped()); |
| size_t bufferOffset = baseInstance * static_cast<size_t>(instanceStride); |
| int attribIdx = program->numVertexAttributes(); |
| for (int i = 0; i < program->numInstanceAttributes(); ++i, ++attribIdx) { |
| const auto& attrib = program->instanceAttribute(i); |
| static constexpr int kDivisor = 1; |
| fAttribArrayState->set(fGpu, attrib.fLocation, instanceBuffer, attrib.fCPUType, |
| attrib.fGPUType, instanceStride, bufferOffset + attrib.fOffset, |
| kDivisor); |
| } |
| } |
| } |
| |
| void GrGLOpsRenderPass::bindVertexBuffer(const GrBuffer* vertexBuffer, int baseVertex) { |
| GrGLProgram* program = fGpu->currentProgram(); |
| SkASSERT(program); |
| if (int vertexStride = program->vertexStride()) { |
| SkASSERT(vertexBuffer); |
| SkASSERT(vertexBuffer->isCpuBuffer() || |
| !static_cast<const GrGpuBuffer*>(vertexBuffer)->isMapped()); |
| size_t bufferOffset = baseVertex * static_cast<size_t>(vertexStride); |
| for (int i = 0; i < program->numVertexAttributes(); ++i) { |
| const auto& attrib = program->vertexAttribute(i); |
| static constexpr int kDivisor = 0; |
| fAttribArrayState->set(fGpu, attrib.fLocation, vertexBuffer, attrib.fCPUType, |
| attrib.fGPUType, vertexStride, bufferOffset + attrib.fOffset, |
| kDivisor); |
| } |
| } |
| } |
| |
| void GrGLOpsRenderPass::onDraw(int vertexCount, int baseVertex) { |
| SkASSERT(!fActiveVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken()); |
| if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) { |
| this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex); |
| baseVertex = 0; |
| } |
| fGpu->drawArrays(fPrimitiveType, baseVertex, vertexCount); |
| } |
| |
| void GrGLOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, |
| uint16_t maxIndexValue, int baseVertex) { |
| if (fGpu->glCaps().baseVertexBaseInstanceSupport()) { |
| SkASSERT(!fActiveVertexBuffer); |
| if (baseVertex != 0) { |
| fGpu->drawElementsInstancedBaseVertexBaseInstance( |
| fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, |
| this->offsetForBaseIndex(baseIndex), 1, baseVertex, 0); |
| return; |
| } |
| } else { |
| this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex); |
| } |
| |
| if (fGpu->glCaps().drawRangeElementsSupport()) { |
| fGpu->drawRangeElements(fPrimitiveType, minIndexValue, maxIndexValue, indexCount, |
| GR_GL_UNSIGNED_SHORT, this->offsetForBaseIndex(baseIndex)); |
| } else { |
| fGpu->drawElements(fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, |
| this->offsetForBaseIndex(baseIndex)); |
| } |
| } |
| |
| void GrGLOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, |
| int baseVertex) { |
| SkASSERT(!fActiveVertexBuffer || fGpu->glCaps().drawArraysBaseVertexIsBroken()); |
| if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) { |
| // We weren't able to bind the vertex buffer during onBindBuffers because of a driver bug |
| // affecting glDrawArrays. |
| this->bindVertexBuffer(fActiveVertexBuffer.get(), 0); |
| } |
| int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount); |
| for (int i = 0; i < instanceCount; i += maxInstances) { |
| int instanceCountForDraw = std::min(instanceCount - i, maxInstances); |
| int baseInstanceForDraw = baseInstance + i; |
| if (fGpu->glCaps().baseVertexBaseInstanceSupport()) { |
| SkASSERT(!fActiveInstanceBuffer); |
| fGpu->drawArraysInstancedBaseInstance(fPrimitiveType, baseVertex, vertexCount, |
| instanceCountForDraw, baseInstanceForDraw); |
| } else { |
| this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw); |
| fGpu->drawArraysInstanced(fPrimitiveType, baseVertex, vertexCount, |
| instanceCountForDraw); |
| } |
| } |
| } |
| |
| void GrGLOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, |
| int baseInstance, int baseVertex) { |
| int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount); |
| for (int i = 0; i < instanceCount; i += maxInstances) { |
| int instanceCountForDraw = std::min(instanceCount - i, maxInstances); |
| int baseInstanceForDraw = baseInstance + i; |
| if (fGpu->glCaps().baseVertexBaseInstanceSupport()) { |
| SkASSERT(!fActiveInstanceBuffer); |
| SkASSERT(!fActiveVertexBuffer); |
| fGpu->drawElementsInstancedBaseVertexBaseInstance( |
| fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, |
| this->offsetForBaseIndex(baseIndex), instanceCountForDraw, baseVertex, |
| baseInstanceForDraw); |
| } else { |
| this->bindInstanceBuffer(fActiveInstanceBuffer.get(), baseInstanceForDraw); |
| this->bindVertexBuffer(fActiveVertexBuffer.get(), baseVertex); |
| fGpu->drawElementsInstanced(fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT, |
| this->offsetForBaseIndex(baseIndex), instanceCountForDraw); |
| } |
| } |
| } |
| |
| void GrGLOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { |
| fGpu->clear(clip, color, fRenderTarget, fOrigin); |
| } |
| |
| void GrGLOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, |
| bool insideStencilMask) { |
| fGpu->clearStencilClip(clip, insideStencilMask, fRenderTarget, fOrigin); |
| } |
| |