blob: 48fc8a7f48a8aa3c0905db0c293f8b4215285e5e [file] [log] [blame]
/*
* Copyright 2019 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/dawn/GrDawnOpsRenderPass.h"
#include "src/gpu/GrFixedClip.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrPipeline.h"
#include "src/gpu/GrRenderTargetPriv.h"
#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/dawn/GrDawnBuffer.h"
#include "src/gpu/dawn/GrDawnGpu.h"
#include "src/gpu/dawn/GrDawnProgramBuilder.h"
#include "src/gpu/dawn/GrDawnRenderTarget.h"
#include "src/gpu/dawn/GrDawnStencilAttachment.h"
#include "src/gpu/dawn/GrDawnTexture.h"
#include "src/gpu/dawn/GrDawnUtil.h"
#include "src/sksl/SkSLCompiler.h"
////////////////////////////////////////////////////////////////////////////////
static dawn::LoadOp to_dawn_load_op(GrLoadOp loadOp) {
switch (loadOp) {
case GrLoadOp::kLoad:
return dawn::LoadOp::Load;
case GrLoadOp::kDiscard:
// Use LoadOp::Load to emulate DontCare.
// Dawn doesn't have DontCare, for security reasons.
// Load should be equivalent to DontCare for desktop; Clear would
// probably be better for tilers. If Dawn does add DontCare
// as an extension, use it here.
return dawn::LoadOp::Load;
case GrLoadOp::kClear:
return dawn::LoadOp::Clear;
default:
SK_ABORT("Invalid LoadOp");
}
}
GrDawnOpsRenderPass::GrDawnOpsRenderPass(GrDawnGpu* gpu, GrRenderTarget* rt, GrSurfaceOrigin origin,
const LoadAndStoreInfo& colorInfo,
const StencilLoadAndStoreInfo& stencilInfo)
: INHERITED(rt, origin)
, fGpu(gpu)
, fColorInfo(colorInfo) {
fEncoder = fGpu->device().CreateCommandEncoder();
dawn::LoadOp colorOp = to_dawn_load_op(colorInfo.fLoadOp);
dawn::LoadOp stencilOp = to_dawn_load_op(stencilInfo.fLoadOp);
fPassEncoder = beginRenderPass(colorOp, stencilOp);
}
dawn::RenderPassEncoder GrDawnOpsRenderPass::beginRenderPass(dawn::LoadOp colorOp,
dawn::LoadOp stencilOp) {
dawn::Texture texture = static_cast<GrDawnRenderTarget*>(fRenderTarget)->texture();
auto stencilAttachment = static_cast<GrDawnStencilAttachment*>(
fRenderTarget->renderTargetPriv().getStencilAttachment());
dawn::TextureView colorView = texture.CreateView();
const float *c = fColorInfo.fClearColor.vec();
dawn::RenderPassColorAttachmentDescriptor colorAttachment;
colorAttachment.attachment = colorView;
colorAttachment.resolveTarget = nullptr;
colorAttachment.clearColor = { c[0], c[1], c[2], c[3] };
colorAttachment.loadOp = colorOp;
colorAttachment.storeOp = dawn::StoreOp::Store;
dawn::RenderPassColorAttachmentDescriptor* colorAttachments = { &colorAttachment };
dawn::RenderPassDescriptor renderPassDescriptor;
renderPassDescriptor.colorAttachmentCount = 1;
renderPassDescriptor.colorAttachments = colorAttachments;
if (stencilAttachment) {
dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
depthStencilAttachment.attachment = stencilAttachment->view();
depthStencilAttachment.depthLoadOp = stencilOp;
depthStencilAttachment.stencilLoadOp = stencilOp;
depthStencilAttachment.clearDepth = 1.0f;
depthStencilAttachment.clearStencil = 0;
depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
} else {
renderPassDescriptor.depthStencilAttachment = nullptr;
}
return fEncoder.BeginRenderPass(&renderPassDescriptor);
}
GrDawnOpsRenderPass::~GrDawnOpsRenderPass() {
}
GrGpu* GrDawnOpsRenderPass::gpu() { return fGpu; }
void GrDawnOpsRenderPass::end() {
fPassEncoder.EndPass();
}
void GrDawnOpsRenderPass::submit() {
fGpu->appendCommandBuffer(fEncoder.Finish());
}
void GrDawnOpsRenderPass::insertEventMarker(const char* msg) {
SkASSERT(!"unimplemented");
}
void GrDawnOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
fPassEncoder.EndPass();
fPassEncoder = beginRenderPass(dawn::LoadOp::Load, dawn::LoadOp::Clear);
}
void GrDawnOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
fPassEncoder.EndPass();
fPassEncoder = beginRenderPass(dawn::LoadOp::Clear, dawn::LoadOp::Load);
}
////////////////////////////////////////////////////////////////////////////////
void GrDawnOpsRenderPass::inlineUpload(GrOpFlushState* state,
GrDeferredTextureUploadFn& upload) {
SkASSERT(!"unimplemented");
}
////////////////////////////////////////////////////////////////////////////////
void GrDawnOpsRenderPass::setScissorState(const GrProgramInfo& programInfo) {
SkIRect rect;
if (programInfo.pipeline().isScissorEnabled()) {
constexpr SkIRect kBogusScissor{0, 0, 1, 1};
rect = programInfo.hasFixedScissor() ? programInfo.fixedScissor() : kBogusScissor;
if (kBottomLeft_GrSurfaceOrigin == fOrigin) {
rect.setXYWH(rect.x(), fRenderTarget->height() - rect.bottom(),
rect.width(), rect.height());
}
} else {
rect = SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
}
fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height());
}
void GrDawnOpsRenderPass::applyState(const GrProgramInfo& programInfo,
const GrPrimitiveType primitiveType) {
sk_sp<GrDawnProgram> program = fGpu->getOrCreateRenderPipeline(fRenderTarget,
programInfo,
primitiveType);
auto bindGroup = program->setData(fGpu, fRenderTarget, programInfo);
fPassEncoder.SetPipeline(program->fRenderPipeline);
fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
const GrPipeline& pipeline = programInfo.pipeline();
if (pipeline.isStencilEnabled()) {
fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fFront.fRef);
}
GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
const float* c = blendInfo.fBlendConstant.vec();
dawn::Color color{c[0], c[1], c[2], c[3]};
fPassEncoder.SetBlendColor(&color);
this->setScissorState(programInfo);
}
void GrDawnOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
const GrMesh meshes[],
int meshCount,
const SkRect& bounds) {
if (!meshCount) {
return;
}
for (int i = 0; i < meshCount; ++i) {
applyState(programInfo, meshes[0].primitiveType());
meshes[i].sendToGpu(this);
}
}
void GrDawnOpsRenderPass::sendInstancedMeshToGpu(GrPrimitiveType,
const GrBuffer* vertexBuffer,
int vertexCount,
int baseVertex,
const GrBuffer* instanceBuffer,
int instanceCount,
int baseInstance) {
dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
fPassEncoder.SetVertexBuffer(0, vb);
fPassEncoder.Draw(vertexCount, 1, baseVertex, baseInstance);
fGpu->stats()->incNumDraws();
}
void GrDawnOpsRenderPass::sendIndexedInstancedMeshToGpu(GrPrimitiveType,
const GrBuffer* indexBuffer,
int indexCount,
int baseIndex,
const GrBuffer* vertexBuffer,
int baseVertex,
const GrBuffer* instanceBuffer,
int instanceCount,
int baseInstance,
GrPrimitiveRestart restart) {
dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
dawn::Buffer ib = static_cast<const GrDawnBuffer*>(indexBuffer)->get();
fPassEncoder.SetIndexBuffer(ib);
fPassEncoder.SetVertexBuffer(0, vb);
fPassEncoder.DrawIndexed(indexCount, 1, baseIndex, baseVertex, baseInstance);
fGpu->stats()->incNumDraws();
}