blob: 260376ee3cf6bd351bcf6e603318196d4d3c380d [file] [log] [blame]
/*
* 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();
if (!program) {
return false;
}
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();
if (!program) {
return;
}
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;
}
}
// We defer binding of instance and vertex buffers because GL does not (always) support base
// instance and/or base vertex.
fActiveInstanceBuffer = sk_ref_sp(instanceBuffer);
fActiveVertexBuffer = sk_ref_sp(vertexBuffer);
}
void GrGLOpsRenderPass::setupGeometry(const GrBuffer* vertexBuffer, int baseVertex,
const GrBuffer* instanceBuffer, int baseInstance) {
GrGLProgram* program = fGpu->currentProgram();
if (!program) {
return;
}
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);
}
}
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::onDraw(int vertexCount, int baseVertex) {
if (fGpu->glCaps().drawArraysBaseVertexIsBroken()) {
this->setupGeometry(fActiveVertexBuffer.get(), baseVertex, nullptr, 0);
fGpu->drawArrays(fPrimitiveType, 0, vertexCount);
return;
}
this->setupGeometry(fActiveVertexBuffer.get(), 0, nullptr, 0);
fGpu->drawArrays(fPrimitiveType, baseVertex, vertexCount);
}
void GrGLOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
uint16_t maxIndexValue, int baseVertex) {
this->setupGeometry(fActiveVertexBuffer.get(), baseVertex, nullptr, 0);
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) {
int maxInstances = fGpu->glCaps().maxInstancesPerDrawWithoutCrashing(instanceCount);
for (int i = 0; i < instanceCount; i += maxInstances) {
this->setupGeometry(fActiveVertexBuffer.get(), 0, fActiveInstanceBuffer.get(),
baseInstance + i);
fGpu->drawArraysInstanced(fPrimitiveType, baseVertex, vertexCount,
std::min(instanceCount - i, maxInstances));
}
}
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) {
this->setupGeometry(fActiveVertexBuffer.get(), baseVertex, fActiveInstanceBuffer.get(),
baseInstance + i);
fGpu->drawElementsInstanced(fPrimitiveType, indexCount, GR_GL_UNSIGNED_SHORT,
this->offsetForBaseIndex(baseIndex),
std::min(instanceCount - i, maxInstances));
}
}
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);
}